go route는 flutter에서 페이지 간 이동 시 URL기반의 API를 이용해서 쉽게 이동할 수 있도록 도와주는 패키지입니다.
1. Go Router 설정하기
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/classA',
builder: (context, state) => ClassA(),
),
GoRoute(
path: '/classB',
builder: (context, state) => ClassB(),
),
],
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
title: 'Go router',
);
}
}
go_router를 이용하기 위해서는 먼저 MaterialApp 위젯을 MaterialApp.router로 변경해 줍니다.
* 이제 routerConfig 프로퍼티를 설정할 수 있게 되었습니다.
이제 GoRouter 오브젝트 타입의 _router를 정의하여 routerConfig에 추가합니다.
GoRouter에 페이지를 각각 추가합니다.
'/' route에 접근 시 HomePage로 연결하며, '/classA', '/classB' route에 접근 시에 각각 ClassA, ClassB로 연결되도록 구성하였습니다.
2. 페이지 간 이동하기
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('HomePage'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.go('/classA'),
child: const Text('classA'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => context.push('/classB'),
child: const Text('classB'),
),
],
),
),
);
}
}
Homepage에는 'classA'와 'classB'라고 이름붙인 두 개의 버튼이 있습니다. 페이지를 이동할 때 위와 같이 context.go()나 context.push() 메서드를 이용해서 이동할 수 있습니다. 그리고 전달 인자로 앞서 GoRouter에서 정의한 URL을 적어주시면 됩니다. 주의할 것은 URL 작성 시 문자열 앞에 꼭 '/'를 같이 입력해 주어야 한다는 점입니다. (이후 Named router에서 /가 없는 표기법을 이야기할 예정입니다.)
눈치채셨겠지만 지금 classA 버튼과 classB 버튼은 서로 이동하는 방식이 다릅니다. context.go와 context.push의 방식은 페이지가 쌓이는 방식의 차이로 이해하시면 되는데요. go는 현재의 페이지를 대체하는 새로운 페이지로 새롭게 렌더링이 되는 개념이라면 push는 현재의 페이지 위에 새로운 페이지를 적층하는 형태입니다. 따라서 context.go로 이동하는 classA의 경우 다시 Homepage로 이동하기 위해서는 별도의 UI를 만들어 줘야 하며, classB의 경우는 AppBar에 뒤로가기 버튼이 자동으로 생성되는 것을 볼 수 있습니다.
3. Subroutes : 서브 루트
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/classA',
builder: (context, state) => ClassA(),
routes: [
GoRoute(
path : 'studentA',
builder: (context, state) => StudentA(),
),
],
),
GoRoute(
path: '/classB',
builder: (context, state) => ClassB(),
),
],
);
페이지 간 트리 구조로 연결되어 있을 경우 subroute를 이용해서 구성할 수 있습니다.
classA 아래에 studentA, classB 아래에 studentB가 있을 경우 각각 별도의 router를 설정하게 되면 '/classA/studentA', '/classB/studnetB'와 같이 설정이 필요한 경우가 있습니다. 특히나 push 메서드를 이용할 경우 트리구조를 이용한 페이지 구성이 중요해지죠. 이런 경우 classA, classB 아래에 서브루트를 설정하면 path를 단순히 'studentA', 'studentB'로 설정만 해 주면 됩니다. 여기서 중요한 것을 subrouter의 경우 path 앞에 /(슬래시)를 입력하지 않습니다.
class ClassA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('ClassA'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.go('/classA/studentA'),
child: const Text('studentA'),
),
],
),
),
);
}
}
class StudentA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('StudentA'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
const Text('This is Student A')
],
),
),
);
}
}
이제 ClassA 페이지에서 studentA 버튼을 클릭 시 '/classA/sutdentA'로 이동하도록 하면 됩니다.
이번에는 context.go 를 이용해서 이동했음에도 불구하고 뒤로가기 버튼이 생성된 것을 볼 수 있습니다. subroute의 경우 context.push와 같은 효과를 나타낼 수 있습니다.
4. Named Router 이용
URL이 길어지고 복잡해질 수록 입력하는 과정에서 실수할 수 있는 가능성이 높아지게 됩니다. 따라서 각각의 router별로 별명을 설정하고 이를 대신하여 사용할 수 있는데 이를 Named Router라고 합니다. Named Router를 사용하는 방법은 기존의 context.go() 대신에 context.goNamed()로 바꿔주면 됩니다.
classB와 studentB를 Named Router를 이용해서 구성해 보도록 하겠습니다. 앞선 classA와 studentA의 구조와 동일하며, 다만 Named Router를 이용한 차이만 있습니다. context.go는 context.goNamed로 바꾼것처럼 context.push는 context.pushNamed로 바꿔주면 됩니다.
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/classA',
builder: (context, state) => ClassA(),
routes: [
GoRoute(
path : 'studentA',
builder: (context, state) => StudentA(),
),
],
),
GoRoute(
name : 'classB',
path: '/classB',
builder: (context, state) => ClassB(),
routes : [
GoRoute(
name: 'studentB',
path: 'studentB',
builder: (context, state) => StudentB(),
),
],
),
],
);
class ClassB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('ClassB'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.pushNamed('studentB'),
child: const Text('studentB'),
),
],
),
),
);
}
}
Named Router의 다른점이라면 기존에 studentA에 접근하기 위해서는 경로를 모두 써 줘야 했는데 ('/classA/studentA'), Named Router에서는 설정한 name만 작성해주면 됩니다. ('studentB') 이로써 발생할 수 있는 에러를 많이 줄일 수 있습니다.
다음 시간에는 Go Router를 이용해서 페이지 간 데이터를 전달하는 방법에 대해서 알아보도록 하겠습니다.
아래는 전체 코드 입니다.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
),
GoRoute(
path: '/classA',
builder: (context, state) => ClassA(),
routes: [
GoRoute(
path : 'studentA',
builder: (context, state) => StudentA(),
),
],
),
GoRoute(
name : 'classB',
path: '/classB',
builder: (context, state) => ClassB(),
routes : [
GoRoute(
name: 'studentB',
path: 'studentB',
builder: (context, state) => StudentB(),
),
],
),
],
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
title: 'Go router',
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('HomePage'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.go('/classA'),
child: const Text('classA'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => context.pushNamed('classB'),
child: const Text('classB'),
),
],
),
),
);
}
}
class ClassA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('ClassA'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.go('/classA/studentA'),
child: const Text('studentA'),
),
],
),
),
);
}
}
class StudentA extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('StudentA'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
const Text('This is Student A')
],
),
),
);
}
}
class ClassB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('ClassB'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => context.pushNamed('studentB'),
child: const Text('studentB'),
),
],
),
),
);
}
}
class StudentB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar : AppBar (
title: const Text('StudentB'),
),
body : Center(
child : Column(
mainAxisAlignment : MainAxisAlignment.center,
children: [
const Text('This is Student B'),
],
),
),
);
}
}
Reference
'프로그래밍 > Flutter & Dart' 카테고리의 다른 글
[Flutter] 보이지 않는 위젯(layout widget) (0) | 2022.12.31 |
---|---|
[Flutter] const, final의 차이점(feat. immutable, stateless vs stateful 차이점) (0) | 2022.12.30 |
[Flutter] state management(provider) (0) | 2022.12.27 |
Flutter vsCode 완소 세팅방법 (0) | 2022.12.02 |
Flutter (2) | 2022.12.01 |
댓글