flutter 개발진이 홍보하는 goRouter
goRouter는 url path 방식으로 라우팅을 지원하는 패키지이다. 무려 공식 패키지이니, 마음놓고 사용할 수 있겠다.
이 곳에서 install을 진행한다.
다음은 GoRouter 를 정의한 AppRouter 클래스이다. 여기서 route들의 관계와 error시 이동할 Page정의, redirect 등을 정의한다.
//app_router.dart
import 'package:flutter/widgets.dart';
import 'package:go_router/go_router.dart';
class AppRouter {
GoRouter get router => _goRouter;
AppRouter();
late final GoRouter _goRouter = GoRouter(
refreshListenable: AppService(),//redirect 시 사용되는 리스너 이다.
initialLocation: '/home',//제일 처음 보여 줄 route
debugLogDiagnostics: true, //router 정보 콘솔에 출력
errorBuilder: (BuildContext context, GoRouterState state) =>
const ErrorPage(),
//route할 때, error가 발생하면ErrorPage로 route한다.
//이는 커스텀도 가능함!
//또한 state.error.toString()으로 에러메세지 출력가능
routes: <GoRoute>[
GoRoute(
path: '/home',
name: 'home',
builder: (BuildContext context, GoRouterState state) {
return const HomePage();
},
routes: [
/// sub Page를 설정할수 있다.
GoRoute(
path: 'geo',//sub page는 '/'를 생략해야 한다. 아니면 error
builder: (BuildContext context, GoRouterState state) {
return const GeoPage();
},
),
],
),
GoRoute(
path: '/splash',
name: 'splash',
builder: (BuildContext context, GoRouterState state) {
return const SplashPage();
},
),
GoRoute(//id를 넘겨주어 navigarion 하는 방법
path: '/book/:id',
builder: (BuildContext context, GoRouterState state) {
return const BookPage(id : state.params['id']);
},
routes: [
/// sub Page를 설정할수 있다.
GoRoute(
path: 'review',//동일하게 sub rout를 가질 수 있다.
builder: (BuildContext context, GoRouterState state) {
return const ReviewPage();
},
),
],
),
],
//redirect: 에서 앱 init되었는지, 로그인 여부, 세팅 등을 체크후 route한다.
redirect: (BuildContext context, GoRouterState state) {
final homeLocation = '/home';
final splashLocation = '/splash';
final isInitialized = AppService().initialized;
//appService에서는 app 시작전 필요한 것들을 인스턴스화하는 과정을 포함한다.
final isGoingToInit = state.subloc == splashLocation;
/// 앱 시작전 권한, 로그인 여부, 세팅 등을 체크하고 route 한다.
if (!isInitialized && !isGoingToInit) {
return splashLocation;
} else if ((isInitialized && isGoingToInit)) {
return homeLocation;
} else {
// Else Don't do anything
return null;
}
},
);
}
rediect를 담당할 AppService()를 정의해 보자.
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../api/weather_api.dart';
class AppService with ChangeNotifier {
static final AppService _singleton = AppService._internal();
factory AppService() {
return _singleton;
}
AppService._internal();
///AppService 바깥에서 onAppStart를 호출
Future<void> onAppStart() async {
await initialize();
notifyListeners();//중요 : 이게 호출되면 redirect 가 됨!
}
/// 앱을 시작하기 위해 필요한 데이터와 세팅 로딩(오래 걸리는 것)
Future<void> initialize() async {
await Future.delayed(const Duration(seconds: 2));
}
}
go router를 사용하기 위해 MaterialApp을 MaterialApp.router로 바꾸어 정의한다.
build(BuildContext context) {
return ScreenUtilInit(
...
builder: (BuildContext context, Widget? child) {
return MultiProvider(
providers: [// goRouter와 MultiProvider를 함께 사용할 때의 예시
...,
Provider<AppRouter>(create: (_) => AppRouter(appService)),
//AppRouter를 provider에 포함하여 상태관리한다.
ChangeNotifierProvider<AppService>(create: (_) => AppService()),
//redirect 를 담당할 AppService.
],
child: Builder(builder: (context) {
final GoRouter goRouter =
Provider.of<AppRouter>(context, listen: false).router;
return MaterialApp.router(
// route 정보 전달
routeInformationProvider: goRouter.routeInformationProvider,
// URI String을 상태 및 Go Router에서 사용할 수 있는 형태로 변환해주는 함수
routeInformationParser: goRouter.routeInformationParser,
// 위에서 변경된 값으로 실제로 어떤 라우트를 보여줄지 정하는 함수
routerDelegate: goRouter.routerDelegate,
);
}),
);
},
);
}
Widget
이제 goRouter를 사용하여 페이지 간 이동을 해보자.
//아래의 두 코드는 같은 의미이다.
GoRouter.of(context).go('/home');
context.go('/home');
//아래의 두 코드는 같은 의미이다.
GoRouter.of(context).push('/home');
context.push('/home');
A_Page 와 B_Page가 있다고 가정해보자. A에서 B로 이동후, 다시 A로 돌아오는 동작은 아래와 같다.
//using .go
//A_Page.dart
context.go('/B_Page');//A -> B
//B_Page.dart
context.go('/A_Page');//B -> A
//using .push
//A_Page.dart
context.push('/B_Page');//A -> B
//B_Page.dart
context.pop();//B를 pop
bottom navigation을 사용할 때 ShellRoute를 사용한다. 아직 ShellRoute는 사용해 본적이 없어... 나중에 정리하러 들어오겠음!
질문이 하나 있는데요
죄송하지만 보통 처음 화면은 스플래시 화면먼저 띄우지 않나요??
적힌거를 보면 홈화면을 가장 먼저 띄우는 것 처럼 되어잇는데.....
제가 이해를 잘못한건지..ㅠㅠㅠㅠㅠ알려주시면 안될까요?