Flutter에서는 UI 화면간 라우팅 및 딥링크 처리를 위하여 Navigator를 이용합니다. Navigator를 이용해도 훌륭한 라우팅을 구축할 수 있는데요. 더욱 간편하게 라우팅을 구축할 수 있는 go_router 패키지에 대해서 알아보겠습니다.
go_router는 URL을 기반으로 라우팅, 딥 링크를 핸들링할 수 있게 해주는 Flutter용 라우팅 패키지입니다.
go_rotuer를 왜 사용할까?
go_router 패키지 공식문서에서는 아래와 같은 기능을 간편하게 제공한다고 합니다.
- 템플릿 구문(예: "user/:id')을 사용하여 경로 및 쿼리 매개변수 구문 분석
- 목적지에 대한 여러 화면 표시(하위 경로)
- 리다이렉션 지원
- ShellRoute를 통한 여러 Navigator 지원
- Material 및 Cupertino 앱 모두 지원
- Navigator API와의 하위 호환성
1. 쿼리 매개변수
go_router는 웹 서버처럼 URL기반으로 라우팅을 처리합니다. 기존의 Navigator는 라우팅되는 위젯을 반환하거나 혹은 named navigator를 이용하여 라우팅을 관리하였습니다. URL을 기반으로 라우팅을 제공하니 URL상에서의 쿼리 매개변수같은 것들을 라우팅 위젯에 간단하게 제공할 수 있게 해줍니다.
2. 하위 경로
Navaigator는 하위 경로에 개념이 존재하지 않았습니다. 그저, 하위 경로를 개발자가 직접 코드로 작성하였죠. 그렇다보니 여러 라우팅기법을 사용하며 화면을 탐색하거나 뒤로가기를 적용시켜왔습니다. 하지만, go_router를 통해서 하위 경로를 지정할 수 있으니, 라우팅을 통해 두개 이상의 화면을 제공할 수 있습니다.
3. 리다이렉션
로그인상태에 따라서 사용자는 로그인 화면 혹은 메인 화면에 위치해야겠죠? go_router를 통해서 이러한 리다이렉션을 제공할 수 있습니다.
4. ShellRoute
중첩 라우팅처럼 화면의 특정 부분에서 하위 UI로 전환되어야 되는 경우 복잡한 작업이 필요했지만, go_router에서는 ShellRoute를 이용하여 중첩 라우팅을 구성할 수 있습니다.
여기까지 알아보고 이제 사용하는 방법에 대해서 알아보겠습니다.
go_router를 사용하기 위해서는 패키지를 설치해야 합니다.
$ flutter pub add go_router
위 명령어를 통해 패키지를 설치합니다.
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text("Hello!"),
),
);
}
}
위 코드는 HomeScreen의 UI입니다. 가운데에 Hello! 라는 글자가 랜더링 될 것입니다.
이제 go_router를 이용하여 HomeScreen을 초기 화면으로 설정해봅시다. 그러기 위해서는 router를 정의해야 합니다.
final router = GoRouter(
routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
]
);
router를 통해 "/" 경로에 해당하는 HomeScreen을 지정했습니다. 경로는 GoRoute를 통해 지정할 수 있으며, 경로에 해당하는 path, 라우팅되는 UI인 builder를 통해 하위 UI를 반환해야 합니다.
이제 이를 MaterialApp에 지정하면 됩니다.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: router,
);
}
}
MaterialApp에 router를 이용할 수 있게끔 router가 지정되어 있습니다. 이를 선언한 후, routerConfig에 우리가 선언한 route를 정의하면 됩니다.
여러개의 화면을 사용한다면 route에 사용하고자하는 GoRoute를 추가하면 됩니다.
final router = GoRouter(routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: "/second",
builder: (context, state) => const SecondScreen(),
),
]);
위 경우에는 "/" 경로가 우선하여 초기 UI로 지정되지만, 만약 "/second" 경로를 초기 UI로 지정하고 싶다면, initailLocation에 해당 경로의 URL을 지정하면 됩니다.
final router = GoRouter(initialLocation: "/second", routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: "/second",
builder: (context, state) => const SecondScreen(),
),
]);
URL을 이용하면 매개변수와 쿼리 파라미터를 이용할 수 있습니다. 매개변수에는 어떻게 접근할 수 있을까요? SecondScreen은 userId를 전달받아 화면 중앙에 랜더링 시켜보겠습니다.
class SecondScreen extends StatelessWidget {
final String userId;
const SecondScreen({super.key, required this.userId});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(userId),
),
);
}
}
이제, path에 매개변수접근을 위하여 아래와 같이 경로를 지정합니다.
final router = GoRouter(initialLocation: "/second/1234", routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: "/second/:userId",
builder: (context, state) =>
SecondScreen(userId: state.pathParameters["userId"]!),
),
]);
이로써, path를 통해 매개변수를 전달받을 수 있습니다. 이번에는 쿼리 파라미터를 이용해볼까요? 쿼리 파라미터는 path는 변경할 필요없이 이동시에 URL에 쿼리 파라미터를 지정하면 됩니다.
final router = GoRouter(initialLocation: "/second?userId=1234", routes: [
GoRoute(
path: "/",
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: "/second",
builder: (context, state) =>
SecondScreen(userId: state.uri.queryParameters["userId"]!),
),
]);
이로써, 매개변수와 쿼리 파라미터를 이용한 라우팅에 대해서 알아보았습니다.
이제 go_router를 통한 페이지 라우팅에 대해서 알아보겠습니다.
1. 화면 전환
context.go는 새로운 화면으로 전환하는 메소드입니다.
context.go("/second?userId=1234");
이는 push가 아니라 새로운 화면으로 전환되므로 뒤로가기는 제공되지 않습니다.
2. push
push 방식은 말 그대로 push 메소드를 이용하면 됩니다.
context.push("/second?userId=1234");
Naviagator의 push 메소드처럼 뒤로가기를 제공합니다.
3. pop
pop은 페이지 스택에서 현재 페이지를 제거합니다. 이를 통해 뒤로가기를 구현할 수 있습니다.
context.pop();
go_router는 하위 경로를 제공한다고 했습니다. 하위 경로를 지정할 때는 GoRoute 내부에 routes에 경로를 추가해주면 됩니다. 이 경우에 하위 경로는 /를 붙이지 않고 지정해주면됩니다.
final router = GoRouter(initialLocation: "/", routes: [
GoRoute(path: "/", builder: (context, state) => const HomeScreen(), routes: [
GoRoute(
path: "second",
builder: (context, state) =>
SecondScreen(userId: state.uri.queryParameters["userId"]!),
routes: [
GoRoute(
path: "third",
builder: (context, state) => const ThirdScreen(),
),
]),
]),
]);
이제 아래와 같은 코드로 한번에 ThirdScreen으로 이동할 수 있습니다.
context.go("/second/third")
ShellRoute와 리다이렉션은 다음에 또 다루도록 하겠습니다.