go_router ์ฉ๋(=๋ผ์ฐํ
ํจํค์ง ์ฌ์ฉ ๋ชฉ์ )
์ฌ์ค ๋ฐ๋ก ์ด๋ ๊ฒ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์์๋ Navigator ๋ง์ผ๋ก ํ๋ฉด ๋ผ์ฐํ
์ ๊ฐ๋ฅํ๋ค. ํ์ง๋ง url based ๋ ์ด๋ ๋ฐฉ์, ์ฌ๋ฌ ํ๋ซํผ์์ ์ฌ์ฉ๋ ์ ์๋ค๋ ์ , Named routes ๋ฑ ๋ง์ ๋ถ๊ฐ๊ธฐ๋ฅ์ด ์์ด์(=์ฌ์ค ๊ทธ๋งํผ ์์ ์ด ์ ๋๋ก ์ญํ ์ ๋ชปํ๊ณ ์๋ค๋ ์ด์ผ๊ธฐ๊ฐ ๋๋ค) ๋ฐ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
์ go_router ์ฌ์ฉํ๋๊ฐ
Flutter Favorite ์ด๊ณ ์์ฃผ ๋ณดํธ์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. ๋ผ์ฐํฐ ์ด๋ ๊ด๋ จํด์ ์ฌ๋ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ง๋ง ์ฅ๋จ์ ๋ฐ์ง ๊ฒ ์์ด ์ ์ผ ๋ณดํธ์ ์ด์ด์ ์ผ๋จ ์ฑํํ๋ค.
go_router ๊ฐ๋ตํ ์๊ฐ
์ด์ฐจํผ ์๋์ ์ํ ์ฝ๋๋ฅผ ์ฐ๊ธด ํ ๊ฑด๋ฐ ๋ณดํต ์๋ก์ด ์์ ฏ์ ์ธ ๋ ๋๋ ํ๋ฌํฐํ์์ ๋ง๋ ์งง์ ์์ ฏ ์๊ฐ ์์์ ๋จผ์ ๋ณธ๋ค. ์ฒ์ ๋จผ์ ๋ณด๊ณ ๋๋ฌด๋ฅผ ๋ณผ ์ ์์ด์ ์ข๋ค. ๋๋ถ๋ถ์ ์์ ฏ ์๊ฐ ์์๋ค์ด ๊น๋ํ๊ฒ ์๊ฐํ ๋์ด ์์ด์ ์ด๋ค ์ฉ๋์ธ์ง, ๊ฐ๋ตํ๊ฒ๋๋ง ์ด๋ค์์ผ๋ก ์ฐ๋์ง ๋ฑ์ ๋น ๋ฅธ ์๊ฐ ๋ด์ ํ์
ํ ์ ์๋ค.
go_router ๊ตฌํ
flutter pub add go_router
class RouterLocation {
static const String splash = '/';
static const String signIn = 'singIn';
}
import 'package:go_router/go_router.dart';
import '../../barrel.dart';
import '../environments/environment.dart';
class RouterConfiguration {
static final GoRoute signIn = GoRoute(
path: RouterLocation.signIn,
name: RouterLocation.signIn,
builder: (context, state) {
return const SignInScreen();
},
);
static final GoRouter router = GoRouter(
initialLocation: RouterLocation.splash,
debugLogDiagnostics: Environment.isProduction ? false : true,
routes: [
GoRoute(
path: RouterLocation.splash,
name: RouterLocation.splash,
builder: (context, state) {
return const SplashScreen();
},
routes: [
signIn,
],
),
],
);
}
๊ทธ๋ฆฌ๊ณ environment ์์ ํธ์ถํ๋ ์์ ฏ์ ์๋์ ๊ฐ์ด ๊ตฌํํ๋ค.
run() async {
await Injector.registerDependencies();
runApp(const ProjectName());
}
import 'package:flutter/material.dart';
import '../../barrel.dart';
class ProjectName extends StatefulWidget {
const ProjectName({super.key});
@override
_ProjectNameState createState() => _ProjectNameState();
}
class _ProjectNameState extends State<ProjectName> {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: RouterConfiguration.router,
);
}
}
go, push ์ฐจ์ด ํ์คํ ์๊ธฐ
ํ๋ฉด์ ์คํ๊ตฌ์กฐ๋ก ๋์ด์๋ค. push ๋ก ์ด๋ํ๋ฉด ํ์ฌ ํ๋ฉด ์คํ์ ์ ๊ท ํ๋ฉด์ ์๋ ํ์์ด๋ค. ๋ฐ๋๋ก go ๋ก ์ด๋ํ๋ฉด ํ์ฌ์ ํ๋ฉด์ ๊ต์ฒดํ๋ ๊ฒ์ด๋ค.
์ด ์๋ฆฌ์ ์ฐ๊ฒฐํ์ฌ GoRoute์ routes[] ์ ๋ํด์ ์์๋ฌ์ผํ๋ค. go ๋ก ์ด๋ํ๋ ๊ฒ์ ์คํ์ ์๋ ๊ฒ์ด ์๋๋ผ ๊ต์ฒดํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋
๋ฆฝ์ ์ธ ๋ฃจํธ๋ ๋ฒจ๋ก ๋ผ์ฐํธ๊ฐ ์กด์ฌํด๋ ๋๋ค. ํ์ง๋ง push ๋ก ์๋ ๊ฒ์ ๋ฐ๋์ ์์ ์์ ฏ์ด ํ์ ์์ ฏ์ ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ๋ง ์์ ์ ์๋ค.
์๋ฅผ ๋ค์ด A์์ ฏ์์ B์์ ฏ์ผ๋ก go ๋ก ์ด๋ํ๋ ๊ฒฝ์ฐ ๋
๋ฆฝ์ ์ธ ๋ฃจํธ๋ฅผ ๊ฐ์ง๊ณ ์์ด๋ ์๊ด์ด ์๋ค. ํ์ง๋ง A์์ push ๋ก B๋ฅผ ์์ ์ฌ๋ฆฌ๊ณ ์ถ์ ๊ฒฝ์ฐ์ A๋ ๋ฐ๋์ ํ์ ์์ ฏ์ผ๋ก B๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ค. routes ๋ฐฐ์ด ๋ด์ B๊ฐ ๋ค์ด๊ฐ ์์ด์ผ ํ๋ค๋ ๋ป์ด๋ค.
go_router ํ์ฉํ์ฌ ๋ฐ์ดํฐ ๋๊ธฐ๊ธฐ
๋จ์ํ ์ฌ์ฉ๋ฒ ์์ค์ด๋ผ์ ํ๋ก์ ํธ์ ์ค์ ๊ตฌํํ๋ ์ฝ๋๋ฅผ ์์ ๋ก ๋จ๊ธด๋ค.
path ๋ฅผ ํตํ ๋ฐ์ดํฐ ์ ๋ฌ
onPressed: () async {
String path = _currentSubMenuType == SubMenuType.normalLounge
? RouterLocation.createPost
: '${RouterLocation.createPostGroup}/:id';
final refreshRequired = await context.pushNamed(
path,
pathParameters: _selectedGroupId != null
? {'id': _selectedGroupId.toString()}
: {},
extra: _currentSubMenuType == SubMenuType.normalLounge
? PostType.lounge
: PostType.group,
);
if ((refreshRequired != null) &&
((refreshRequired as List<bool>).first)) {
if (_currentSubMenuType == SubMenuType.normalLounge) {
Future.microtask(() => context
.read<PostBloc>()
.add(NormalLoungeSubMenuRequested.initial()));
} else {
Future.microtask(() => context
.read<PostBloc>()
.add(GroupLoungeSubMenuRequested.initial()));
}
}
},
static final GoRoute createPostGroup = GoRoute(
path: '${RouterLocation.createPostGroup}/:id',
name: '${RouterLocation.createPostGroup}/:id',
builder: (context, state) {
final String groupId = state.pathParameters['id']!;
final PostType postType = state.extra as PostType;
return BlocProvider<PostBloc>(
create: (_) => PostBloc(
loadingSpinnerBloc: Injector.loadingSpinnerBloc,
postRepository: Injector.postRepository,
groupRepository: Injector.groupRepository,
),
child: CreatePostScreen(
postType: postType,
groupId: postType == PostType.group ? int.parse(groupId) : null,
),
);
},
);// Some code
queryParameter ํตํ ๋ฐ์ดํฐ ์ ๋ฌ
onTap: () async {
final result = await context.pushNamed(
RouterLocation.subComment,
extra: widget.comment,
queryParameters: {
'postId': widget.postId.toString(),
'commentId': widget.comment.id.toString(),
},
);
final refreshRequired = ((result != null) &&
((result as List<bool>).first));
if (refreshRequired) {
widget.commentInfiniteModel!.initialize();
_refreshPost();
}
},
static final GoRoute subComment = GoRoute(
path: RouterLocation.subComment,
name: RouterLocation.subComment,
builder: (context, state) {
final int postId = int.parse(state.queryParameters['postId']!);
final int commentId = int.parse(state.queryParameters['commentId']!);
return BlocProvider<CommentBloc>(
create: (_) => CommentBloc(
loadingSpinnerBloc: Injector.loadingSpinnerBloc,
commentRepository: Injector.commentRepository,
),
child: SubCommentScreen(postId: postId, commentId: commentId),
);
},
);
final rotatedResult = await context.pushNamed(
RouterLocation.imageRotation,
extra: File(imageFile.path),
);
static final GoRoute imageRotation = GoRoute(
path: RouterLocation.imageRotation,
name: RouterLocation.imageRotation,
builder: (context, state) {
final File image = state.extra as File;
return ImageRotationScreen(image: image);
},
);