말랑한 하루

[Flutter] GoRouter 시작하기 본문

개발/Flutter

[Flutter] GoRouter 시작하기

지수는말랑이 2023. 12. 29. 18:34
반응형

※ reference : https://pub.dev/packages/go_router

 

GoRouter는 Flutter의 Router API를 사용하여, 다양한 화면 간 탐색을 위한 편리한 URL기반 API를 제공한다.

URL 패턴 정의, 탐색, 딥 링크 처리 등 다양한 탐색 관련 시나리오를 진행할 수 있다. 주요 특징으로는 다음과 같다.

🍒 Templete 구문(ex, user/:id)을 사용하여 경로 및 Query 매개변수 구문을 분석할 수 있다.

🍒 목적지(하위 경로)에 대한 여러 화면 표시

🍒 Redirection 지원

Application의 State에 따라 사용자를 다른 URL로 다시 Routing할 수 있습니다.

🍒 ShellRoute를 통한 다양한 Navigator 지원

일치하는 경로를 기반으로 자체 페이지를 표시하는 내부 Navigator를 표시할 수 있다. (ex, BottomNavigationBar를 계속 표시하려는 경우)

🍒 Material, Cupertino App 모두 지원

🍒 Navigator API와의 하위 호환성

🐇 GoRouter Install

document: https://pub.dev/packages/go_router/install

flutter에서 다음 명령문으로 간편하게 설치한다.

flutter pub add go_router

이후 flutter pub get 명령문을 실행한다.

이제 Dart 코드에서 다음과 같이 go_router를 사용할 수 있다.

import 'package:go_router/go_router.dart';

🐇 GoRouter Start

※ document : https://pub.dev/documentation/go_router/latest/topics/Get started-topic.html

기본적인 예제는 다음과 같다

//app_router.dart
final _router = GoRouter {
	routes: [
		GoRoute(
			pate: '/',
			builder: (context, state) => Screen(),
		)
	]
}
// main.dart
class MyApp extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return MaterialApp.router(
			routerConfig: _router,
		)
	}
}

🐇 GoRouter Design

go_router를 더 정형화 된 모습으로 사용하기 위해 다음과 같이 설계한다.

 

🥕 Create

🍒 Create File

lib하위 config/util 원하는 폴더에 router.dart를 생성한다.

 

🍒 GlobalKey

생성한 Router에는 NavigatorState를 지닌 GlobalKey를 생성해준다.

GlobalKey는 전체 앱에서 고유한 키다. 가장 큰 특징은 각 요소를 고유하게 식별 한다는 것이다.

BuildContext와 같은 요소들과 연관된 다른 객체에 대한 Access를 제공한다. 만약, StatefulWidget의 경우, 글로벌 키들은 또한 State에 대한 Access를 제공한다.

 

🍒 Create GoRouter

이제 실질적으로 사용할 GoRouter 객체를 생성한다. 주요 속성으로는 navigatorKey, initialLocation, routes가 있다.

navigatorKey에는 GlobalKey를 할당하여, 앱에서 고유한 키의 역할을 하고 다양한 요소를 고유하게 식별 할 수 있게 하자.

initialLocation은 사용자가 처음 App을 시작할 때 route 경로를 지정해주는 것이다.

routes는 GoRoute 객체들을 할당하자.

 

🍒 Create GoRoute

GoRoute 객체는 설정해놓은 path경로로 다양한 옵션과 함께 builder를 사용하여 페이지를 생성해 주는 객체이다. 자세한 내용은 다음과 같다.

(new) GoRoute GoRoute({
  required String path,
  String? name,
  Widget Function(BuildContext, GoRouterState)? builder,
  Page<dynamic> Function(BuildContext, GoRouterState)? pageBuilder,
  GlobalKey<NavigatorState>? parentNavigatorKey,
  FutureOr<String?> Function(BuildContext, GoRouterState)? redirect,
  FutureOr<bool> Function(BuildContext)? onExit,
  List<RouteBase> routes = const <RouteBase>[],
})

pageBuilder와 builder의 차이점은 애니메이션의 유무이다.

 

builder는 화면에 표시할 위젯을 만드는 일만 담당하기 때문에, 애니메이션이 자동으로 적용되지 않는다.

하지만, pageBuilder는 해당 경로가 활성화 될 때, 전환 애니메이션을 사용자 정의할 수 있다. 기본적인 전환은 Widget Tree 상단에 있는 App에 따라 페이지간에 사용된다.

 

redirect는 GoRouterRedirect 유형의 콜백입니다. redirection하지 않고 원래 경로로 돌아가기 위해선 null을 반환합니다 예시는 다음과 같습니다

redirect: (BuildContext context, GoRouterState state) {
  if (AuthState.of(context).isSignedIn) {
    return '/signin';
  } else {
    return null;
  }   
},

 

🍒 Wrap up

위 모든 내용을 담은 개발 구성 요소는 다음과 같이 구현해낼 수 있다.

final GlobalKey<NavigatorState> 
	navigatorKey = GlobalKey<NavigatorState>();

GoRouter appRouter = GoRouter(
  navigatorKey: navigatorKey,
  initialLocation: "/",
  routes: <GoRoute>[
    GoRoute(
      path: "/",
      name: "home",
      pageBuilder: (context, state) 
							=> const NoTransitionPage(child: Home()),
    ),
  ],
);

pageBuidler의 NoTransitionPage Widget은 페이지가 변환될 때 어떠한 애니메이션도 적용하지 않겠다는 기능을 했다.

 

위 예제에서 Home 페이지를 반환할 때 매개변수를 주고 싶다면 다음과 같이 활용한다.

Home(id: state.pathParameters['userId']),

또한 Query 문자열 매개변수에 접근하려면 GoRouterState를 사용하자. 예를 들면 다음과 같다.

/users?filter=admins
Home(filter: state.uri.queryParameters["filter"]),

 

🥕 Useage GoRouter

GoRouter를 사용하는 방법은 다음 메소드들을 참고해서 진행하길 바란다.

 

🍒 context.go()

목적지로 바로 이동하는 호출로써, 원하는 URL을 입력하여 사용할 수 있다.

목적지로 이동하면 현재 화면 스택이 목적지 경로에 표시되도록 구성된 화면으로 대체된다.

context.go("/home"),

Query 매개변수로 URI를 작성하려면, Dart 표준 라이브러리 클래스인 Uri 를 사용할 수 있다.

context.go(Uri(path:"/home", 
			queryParameters: {"filter": "login"}).toString()")

 

🍒 context.push() / context.pop()

Navigator의 기록 스택에 화면을 push/pop 할 수 있다. 하지만, 명령형 탐색은 브라우저 기록에 문제를 일으키는 것으로 알려져 있으니 사용에 주의하자.

 

🍒 context.goNamed()

Route의 name속성을 활용해 페이지를 이동하는 방법이다.

 

🥕 Useful StaticConfig

GoRoute 객체와 같은 정보를 담고 있는 StaticConfig Class를 만들어주면 다양한 방면으로 사용할 수 있다.

enum을 List의 Filter로 사용할 수 있는 것과 같은 맥락으로, 현재 Route의 위치와 내부 Widget의 값을 비교하여 다양한 방식으로 이끌어낼 수 있다.

예시는 다음과 같다

class StaticConfig {
	static final List mainNavigator = [
		{
			"path": "/",
			"name": "home",
		},
		{
			"path": "/my",
			"name": "my",
		},
	]
}

 

🍒 Bar 요소의 선택적 가시화

현재 Bar요소의 name과 Route의 name을 비교하여, 요소가 선택되었음을 Color/Animation/Decoration 등을 활용하여 표시할 수 있다.

 

Router의 이동에 따라 navigation과 name 속성 값이 같은 item에 대한 색상을 칠한다고 가정해보자, 그렇다면 우리는 다음과 같은 요소가 필요하다.

  1. GoRouter의 상태값에 포함된 name
  2. 클릭되는 요소의 name

GoRouterState는 Routing 중 경로의 상태를 의미한다. 즉, context에서 현재 경로로 진입하는 Route의 State를 가지고있다 생각하면 편하다.

 

그래서 1)과 2)를 다음과 같이 구할 수 있다.

GoRouterState.of(context).name // 1)
StaticConfig.navigator[i].name

그래서 두 상태 값이 같은 경우와 다른 경우에 색상을 전달해 줄 수 있고, 사용자가 현재 어떤 페이지에 존재하는지 navigator에서 확연하게 볼 수 있다.

 

🥕 GoRouter Start

모든 설정이 완료되었다면, Router를 앱에 적용시키자.

class _MyAppState extends State<MyApp> {
  ...

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
			...
      routerConfig: app_router,
    );
  }
}

router에 관한 추가적인 설정을 할 수 있는데, 내용은 다음과 같다.

 

🍒 routeInformationProvider: _router.routerInformationProvider

Route 정보 전달

 

🍒 routeInformationParser: _router.routeInformationParser

URI String을 State 및 GoRouter에서 사용할 수 있는 형태로 변환해주는 함수

 

🍒 routerDelegate: _router.routerDelegate

URI로 변경된 값을 활용해 실제로 어떤 라우트를 보여줄지 결정하는 함수

 

추후엔 위 3가지 정보와 유저의 로그인 상태를 활용해서 GoRouter를 마이그레이션 할 수 있다. 먼저 시도해보고 싶은 사람은 다음 블로그를 참고하여(https://dev-yongsu.tistory.com/17) 시도해보길 바란다.

반응형
Comments