말랑한 하루
[Flutter] GoRouter 시작하기 본문
※ 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에 대한 색상을 칠한다고 가정해보자, 그렇다면 우리는 다음과 같은 요소가 필요하다.
- GoRouter의 상태값에 포함된 name
- 클릭되는 요소의 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) 시도해보길 바란다.
'개발 > Flutter' 카테고리의 다른 글
[Flutter] Dio 시작하기 (0) | 2023.12.30 |
---|---|
[Flutter] (Error) requires SDK version >=3.2.3 <4.0.0, version solving failed. (0) | 2023.12.30 |
[Flutter] AsyncValue? (0) | 2023.12.28 |
[Flutter] Riverpod의 (Async)NotifierProvider (0) | 2023.12.28 |
[Flutter] Riverpod 그리고 Provider (0) | 2023.12.27 |