GoRouter
앱 내에서 네비게이션과 라우팅을 관리하기 위한 패키지 중 하나로, 이 패키지는 플러터 앱의 다양한 화면 간 전환 및 경로 관리를 도와주는 라우팅 라이브러리로 사용된다. GoRouter는 다른 라우팅 패키지와 비교하여 간편한 구성 및 빠른 성능을 제공하는 것으로 알려져 있다.
dependencies:
flutter:
sdk: flutter
go_router:
GoRouter를 사용하기 위해서는 go_router를 추가 해야 한다.
import 'package:go_router/go_router.dart';
import 'package:go_router_practice/screens/root_screen.dart';
final router = GoRouter(
routes: [
GoRoute(path: '/', builder: (context, state) => const RootScreen()),
],
);
우선 앱에서 사용할 router를 생성해야한다. 원하는 페이지로 이동 하고 싶다면 routes에 GoRoute를 등록해주면된다.
import 'package:flutter/material.dart';
import 'package:go_router_practice/route/router.dart';
void main() {
runApp(const _App());
}
class _App extends StatelessWidget {
const _App({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: router,
);
}
}
MaterialApp 대신 MaterialApp.router를 이용해서 router를 등록했다.
GoRouterState.of(context)를 이용하게 되면 현재 라우터의 상태에 접근할수 있다. State를 이용하게 되면 path,uri,error,pathParamer등을 이용하여 현재 라우터의 상태를 알수 있다.
router.dart
GoRoute(
path: 'use_basic',
builder: (context, state) => const UseBasicScreen(),
),
GoRoute(
path: 'use_named',
name: 'use_named_screen',
builder: (context, state) => const UseNamedScreen(),
),
GoRoute(
path: 'use_push',
builder: (context, state) => const UsePushScreen(),
),
우선 라우터 등록이 필요하다.
root_screen.dart
ElevatedButton(
onPressed: () {
context.go('/use_basic');
},
child: const Text('Go Basic'),
),
ElevatedButton(
onPressed: () {
context.goNamed('use_named_screen');
},
child: const Text('Go Named'),
),
ElevatedButton(
onPressed: () {
context.push('/use_push');
},
child: const Text('Go Push'),
),
우선 가장 기본적인 페이지 이동방법이다. 보통 이렇게 세가지 방법으로 사용을 하게되는데, path가 너무 길어질 경우 goNamed를 이용을 한다. 그렇다면 .go()랑 .push()의 비슷해 보이는데 무슨 차이가 있는것일까??
go : go는 기존 라우트에 새로운 라우터를 새로 생성하는 방식으로 스택에 쌓이지 않는다. 그래서 새로운 라우터에서 뒤로가기를 하게되면 '/' 라우트로 돌아간다.
push : push는 기존 라우트에 새로운 라우터를 올리는 방식으로 스택에 쌓인다. 그래서 새로운 라우터에선 뒤로가기를 하게되면 '/' 이전 새로운 라우터를 올리기전 라우터로 이동하게 된다.
pop_base_screen.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_practice/layout/defaul_layout.dart';
class PopBaseScreen extends StatelessWidget {
const PopBaseScreen({super.key});
@override
Widget build(BuildContext context) {
return DefaultLayout(
body: ListView(
children: [
ElevatedButton(
onPressed: () async {
final result = await context.push('/pop/return');
print(result);
},
child: const Text('Push Pop Return Screen')),
],
));
}
}
pop_return_screen.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_practice/layout/defaul_layout.dart';
class PopReturnScreen extends StatelessWidget {
const PopReturnScreen({super.key});
@override
Widget build(BuildContext context) {
return DefaultLayout(
body: ListView(
children: [
ElevatedButton(
onPressed: () {
context.pop('Pyo');
},
child: const Text('pop'))
],
));
}
}
기존 .push()를 사용해서 새로운 라우터에서 뒤로가기를 했을때의 역할을 하게된다. await/async 를 이용하게 되면 새로운 라우터에서 기존 라우터로 데이터를 받아올수 있다.
router.dart
GoRoute(
// PATH : /path_param/:id
path: 'path_param/:id',
builder: (context, state) => const PathParamsScreen(),
routes: [
GoRoute(
// PATH : /path_params/:id/:name
path: ':name',
builder: (context, state) => const PathParamsScreen(),
),
],
),
GoRoute(
// PATH : /query_param
path: 'query_param',
builder: (context, state) => const QueryParamScreen(),
),
path_param_screen.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_practice/layout/defaul_layout.dart';
class PathParamsScreen extends StatelessWidget {
const PathParamsScreen({super.key});
@override
Widget build(BuildContext context) {
return DefaultLayout(
body: ListView(
children: [
Text('Path Param : ${GoRouterState.of(context).pathParameters}'),
ElevatedButton(
onPressed: () {
context.go('/path_param/123/Pyo');
},
child: const Text('Path Param'),
),
],
));
}
}
GoRouter에서 PathParamter를 이용하여 sub경로를 넣어주는 방법이다. 라우터 등록시 Path 지정 필요 /: -> /id
위 코드를 실행한 결과이다.
query_param_screen.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:go_router_practice/layout/defaul_layout.dart';
class QueryParamScreen extends StatelessWidget {
const QueryParamScreen({super.key});
@override
Widget build(BuildContext context) {
return DefaultLayout(
body: ListView(
children: [
ElevatedButton(
onPressed: () {
context.go(Uri(
path: '/query_param',
queryParameters: {'id': '123', 'name': 'Pyo'}).toString());
},
child: const Text('Query Param'))
],
),
);
}
}
QureyParameter를 사용할수도 있다. 라우터 등록시 Path 지정 안해줘도됨 -> ?id
실제 웹이 아닌 이상 앱에서는 query 파라미터보다는 path 파라미터를 많이 사용한다고 한다.
그래서 path 파라미터를 사용했던 예제 코드를 정리하려고 한다.
// GoRoute 지정
GoRoute(
path: 'product/:rid',
name: ProductDetailScreen.routeName,
builder: (_, state) =>
ProductDetailScreen(id: state.pathParameters['rid']!),
),
// goRouter를 통해 화면 이동
context.go('/product/${id}')
context.goNamed(ProductDetailScreen.routeName,
pathParameters: {'rid': model.id});
context.go()를 이용하게 되면 GoRoute()에서 지정한 path뒤에 id값만 붙여주면 되지만 goName()를 이용한다면 위 코드처럼 pathParameter를 이용하면 된다.
여기 까지 goRouter를 이용하여 기본적인 route 기능에 대해 정리해봤다. 다음에는 실제 프로젝트에서 유용하게 사용할수 있는 shellRouter,redirect,error & logging에 대해 정리를 해보겠다.
참고
https://www.inflearn.com/course/%ED%94%8C%EB%9F%AC%ED%84%B0-%EC%8B%A4%EC%A0%84/dashboard