๐ŸŽ๏ธ [Flutter] Go Router ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ

Tygerยท2024๋…„ 2์›” 12์ผ
3

Flutter

๋ชฉ๋ก ๋ณด๊ธฐ
53/57
post-thumbnail

๐ŸŽ๏ธ Go Router ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ

go_router | Flutter Package

ํ™”๋ฉด ์ด๋™์„ ์œ„ํ•œ ๋ฐฉ๋ฒ• ์ •๋ฆฌ (Router)

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Flutter์—์„œ ๋ผ์šฐํŒ…์„ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€์ธ go_router์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

Flutter ์—์„œ ํ™”๋ฉด ์ „ํ™˜์„ ์ฒ˜๋ฆฌํ•  ๋•Œ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” Navigator๊ฐ€ ์žˆ๋‹ค. Navigator๋Š” ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๋„ ๋ณต์žกํ•˜๊ณ , ์‹ฌํ”Œํ•œ ๋ผ์šฐํŒ… ์ฒด๊ณ„์— ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ๋ถˆํŽธํ•œ ์ ์ด ๋‹ค์†Œ ์žˆ๋‹ค.

์ €๋Š” ์ฃผ๋กœ Get Router๋ฅผ ์‚ฌ์šฉํ•ด ์™”๋Š”๋ฐ, ์ฒ˜์Œ์—๋Š” context ์—†์ด ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋ถ€๋ถ„ ๋•Œ๋ฌธ์— ์žฅ์ ์ด๋ผ ์ƒ๊ฐํ–ˆ์ง€๋งŒ, Get ํŒจํ‚ค์ง€ ์ž์ฒด๊ฐ€ ๊ทœ๋ชจ๊ฐ€ ํฐ ํŒจํ‚ค์ง€์— ์†ํ•˜๋Š” ํŽธ์ด๋ฉด์„œ, ๋ผ์šฐํ„ฐ ๋งŒ์„ ์œ„ํ•ด Get์„ ๋“ฑ๋กํ•œ๋‹ค๋Š” ๊ฒƒ์ด ๋ถ€๋‹ด์ด ๋˜๊ธฐ ์‹œ์ž‘ํ•˜๊ณ , ๊ฐœ์ธ์ ์œผ๋กœ Get ํŒจํ‚ค์ง€์— ๋Œ€ํ•ด์„œ๋Š” ๊ธ์ •์ ์ด์ง€ ์•Š์€ ํŽธ์ด๋ผ ์ƒˆ๋กœ์šด ๋ผ์šฐํ„ฐ๋ฅผ ์ฐพ๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ผ์šฐํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒจํ‚ค์ง€๋Š” ์ด๋ฏธ ๋‹ค์ˆ˜์˜ ํŒจํ‚ค์ง€๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ์—ฌ๋Ÿฌ ๋ผ์šฐํ„ฐ๋“ค์„ ์‚ฌ์šฉํ•ด ๋ณด๋‹ค๊ฐ€ ๊ฐœ์ธ์ ์œผ๋กœ go_router์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ๋งˆ์Œ์— ๋“ค์—ˆ๊ณ , ๊ธฐ์กด ํ”„๋กœ์ ํŠธ๋“ค์„ ๋ฆฌํŽ™ํ•˜๊ธฐ์—๋„ ๋ถ€๋‹ด์ด ์—†์–ด go_router๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ํŽธ์ด๋‹ค.

๋ผ์šฐํ„ฐ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ํ”„๋กœ์ ํŠธ์˜ ํŠน์„ฑ๋งˆ๋‹ค ๋‹ค๋ฅด๊ณ , ๊ฐœ์ธ์˜ ๊ฐœ๋ฐœ ์Šคํƒ€์ผ์ด๋‚˜ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๊ฒฌํ•ด๊ฐ€ ๋‹ค๋ฅด๊ธฐ์— go_router๋Š” ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ๋‚˜ ์ •๋„๋กœ๋งŒ ๋ด์ฃผ์‹œ๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

Go Router

๋ณธ๊ฒฉ์ ์œผ๋กœ go_router์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

Dependencies

go_router ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž. ์ž‘์„ฑ ์‹œ์  ๊ธฐ์ค€ ์ตœ์‹  ๋ฒ„์ „์ธ 13.1.0 ๋ฒ„์ „์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

flutter pub add go_router

dependencies:
	go_router: ^13.1.0

MaterialApp.router

๋จผ์ € Router ์‚ฌ์šฉ์„ ์œ„ํ•ด MaterialApp์„ MaterialApp.router๋กœ ๋ณ€๊ฒฝ์„ ํ•ด์ฃผ๋„๋ก ํ•˜์ž.

๋ผ์šฐํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด .router ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


Widget build(BuildContext context) {
	return MaterialApp.router();
}

MaterialApp.router๋„ ๊ธฐ์กด๊ณผ ๋™์ผํ•œ MaterialApp๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฐจ์ด์ ์ด ์žˆ๋‹ค๋ฉด MaterialApp์€ ๊ฐ„ํŽธํ•˜๊ฒŒ home์„ ์ง€์ •ํ•˜์—ฌ ํ•˜์œ„ ์œ„์ ฏ์„ ์‹œ์ž‘์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด .router์—๋Š” home ์˜ต์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋‹ค.

ํ•„์ˆ˜๋กœ routerConfig๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

MaterialApp.router(
	routerConfig : null
);

RouterConfig

RouterConfig๋ฅผ ์ƒ์„ฑํ•ด ์ค„ ๊ฒƒ์ธ๋ฐ, ํ•ด๋‹น ํด๋ž˜์Šค๋Š” ํ˜ธ์ถœ๋  ์ผ์ด ์—†์–ด์„œ ํด๋ž˜์Šค ๋ช…์€ ์ž์œ ๋กญ๊ฒŒ ์ž‘์„ฑํ•˜์…”๋„ ๋œ๋‹ค.

static ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ์ „์—ญ ๋ฉ”์†Œ๋“œ๋กœ ๋งŒ๋“ค์–ด ์ฃผ์ž.

import 'package:go_router/go_router.dart';

class CustomRouter {
  static GoRouter router = GoRouter(routes: routes);
}

GoRouter ๊ฐ์ฒด๋Š” ํ•„์ˆ˜ ๊ฐ’์œผ๋กœ routes ๊ฐ’์„ ์ „๋‹ฌํ•˜๋ผ๊ณ  ํ•œ๋‹ค.

routes๋Š” RouteBase ํƒ€์ž…์„ ๋ฐฐ์—ด๋กœ ์ „๋‹ฌ ๋ฐ›๊ณ  ์žˆ๋‹ค. HomePage๋ผ๋Š” ๊ธฐ๋ณธ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๊ณ , Router์— ๋“ฑ๋ก์„ ํ•ด์ฃผ์ž.

RouteBase ํƒ€์ž…์€ GoRoute๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ํ•„์ˆ˜ ๊ฐ’์œผ๋กœ path๋ฅผ ์ง€์ •ํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, path๋งŒ ๋“ฑ๋กํ•ด์„œ๋Š” ์‚ฌ์šฉ์ด ๋˜์ง€ ์•Š๊ณ , ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ ์ด์œ ๋Š” ๋‹น์—ฐํ•˜๊ฒŒ๋„ ์œ„์ ฏ์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•ด์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์›ํ•˜๋Š” ๋ผ์šฐํ„ฐ์˜ ํŽ˜์ด์ง€๋ฅผ ๋“ฑ๋กํ•ด ์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด builder, pageBuilder ์ด๋ ‡๊ฒŒ ์žˆ๋Š”๋ฐ, ์ด ๋‘˜์˜ ์ฐจ์ด๋Š” ์•„๋ž˜์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๊ณ , ์šฐ์„ ์€ builder๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

routes: [
	GoRoute(
		path: "/",
        builder: (_, __) => const HomePage(),
      ),
],

์ด์ œ MaterialApp์œผ๋กœ ๋Œ์•„์™€์„œ ์ƒ์„ฑํ•œ RouterConfig๋„ ๋“ฑ๋กํ•ด ์ฃผ๊ณ  ๋นŒ๋“œ๋ฅผ ํ•ด๋ณด์ž. ์ •์ƒ์ ์œผ๋กœ HomePage๋กœ ์ด๋™๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

return MaterialApp.router(
	routerConfig: CustomRouter.router,
);

์ผ๋ฐ˜์ ์œผ๋กœ Navigator๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋„ home์„ ์ง€์ •ํ•ด์ฃผ๊ฑฐ๋‚˜ initialRoute ๋ฅผ ์ง€์ •ํ•˜๋„๋ก ๋˜์–ด์žˆ๋Š”๋ฐ, ์•„๋ฌด ๊ฒƒ๋„ ์ง€์ •ํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ GoRouter๋Š” ๊ธฐ๋ณธ ํŽ˜์ด์ง€๋กœ HomePage๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์„๊นŒ ?

์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋ ค๋ฉด GoRouter์˜ ์ดˆ๊ธฐํ™” ๋ผ์šฐํ„ฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์˜ ์„ค๋ช…์„ ๋ด์•ผํ•œ๋‹ค.

GoRouter์—๋Š” ์˜ต์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ initialLocation์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ์žˆ๋Š”๋ฐ, ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์‚ดํŽด๋ณด๋ฉด ๊ธฐ๋ณธ ๋กœ์ผ€์ด์…˜์ด NULL์ผ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ๋กœ์ผ€์ด์…˜์€ ๋“ฑ๋ก๋œ routes์˜ "/" path๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋˜์–ด์žˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด HomePage์˜ path๋ฅผ "/home" ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋‹ค์‹œ ์‹คํ–‰์„ ํ•ด๋ณด์ž.

ํŽ˜์ด์ง€๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋Š” ์—๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ๋…ธ์ถœ์ด ๋˜์—ˆ๋‹ค.



initialLocation

์œ„์—์„œ ํ…Œ์ŠคํŠธ ํ•ด๋ณธ ๊ฒƒ ์ฒ˜๋Ÿผ initialLocation์œผ๋กœ "/" path๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๋ฉด, ์ง€์ •ํ•ด ์ฃผ์ง€ ์•Š์•„๋„ ๋˜๊ธด ํ•˜์ง€๋งŒ "/home" path ์ฒ˜๋Ÿผ ์›ํ•˜๋Š” path ๊ฒฝ๋กœ๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ฐ’์„ ์ง€์ •ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

static GoRouter router = GoRouter(
	initialLocation: "/home",
	routes: [
    ...
    ],
);

GoRoute

GoRoute์— ๋Œ€ํ•ด์„œ ๊ธฐ๋ณธ์ ์ธ ์‚ฌํ•ญ์„ ์ถ”๊ฐ€์ ์œผ๋กœ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

์ด๋ฒˆ์—๋Š” ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค. FirstPage๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๊ณ , path๋Š” "/first" ๋ผ๊ณ  ํ•ด์ฃผ์—ˆ๋‹ค.

GoRoute(
	path: "/first",
	builder: (_, __) => const FirstPage(),
),

์ด์ œ HomePage์— ๊ฐ„๋‹จํ•œ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด์„œ FirstPage๋กœ ๋ผ์šฐํŒ…์„ ํ•ด์ฃผ๋„๋ก ํ•˜์ž.

go_router์—์„œ ๋ผ์šฐํŒ…์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Navigator๋‚˜ ํƒ€ ํŒจํ‚ค์ง€ ์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ ์•„๋ž˜์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ˆ ์šฐ์„  ๊ธฐ๋ณธ ๋ฐฉ์‹์œผ๋กœ ๋ผ์šฐํŒ…์„ ์ง„ํ–‰ํ•ด ๋ณด์ž.

context๋ฅผ ์‚ฌ์šฉํ•ด go๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ์ด ๋•Œ์— ๋“ฑ๋กํ•œ path๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค. ๋ผ์šฐํŒ…์ด ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

context.go("/first");

์ด๋ฒˆ์—๋Š” named๋กœ ๋ผ์šฐํŒ…์„ ํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ๋„ ๋ผ์šฐํŒ…์„ ํ•ด์ฃผ๋„๋ก ํ•˜์ž. ๋ณด๊ธฐ์—๋Š” context.go์™€ ์ฐจ์ด๊ฐ€ ์—†์–ด ๋ณด์ด์ง€๋งŒ ์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž.

context.goNamed("/first");

ํ•ด๋‹น ๋ฐฉ์‹์œผ๋กœ๋Š” ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ์— ์‹คํŒจํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

ํ•ด๋‹น ์—๋Ÿฌ๋Š” route name์œผ๋กœ "/first"๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. name์„ ๋“ฑ๋กํ•ด์ฃผ๋„๋ก ํ•˜์ž.

GoRoute(
	path: "/first",
    name: "first",
	builder: (_, __) => const FirstPage(),

์ด๋ฒˆ์—๋Š” ์ •์ƒ์ ์œผ๋กœ ๋ผ์šฐํŒ…์— ์„ฑ๊ณตํ•˜์˜€๋‹ค.

GoRouter.of(context).goNamed("first");

์ด์ฒ˜๋Ÿผ path๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๊ณ , name์„ ์ง€์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

path, name ์–ด๋–ค ๊ฑธ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฑธ๊นŒ ? ์•„๋ž˜์—์„œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด๋ฉด ์‰ฝ๊ฒŒ ์ดํ•ด๊ฐ€ ๋  ๊ฒƒ์ธ๋‹ค. path์—๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋™์ ์ธ ๊ฐ’์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด, name์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€๋กœ ๊ฒฝ๋กœ์— ๋„ฃ์„ ์ˆ˜ ์—†๋‹ค.

์ธ์Šคํƒ€ ์•ฑ์„ ๊ฐœ๋ฐœํ•ด์„œ ํ”ผ๋“œ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ด๋ณด์ž.

์ด๋•Œ์— ๊ณต์œ ๋˜๋Š” ํ”ผ๋“œ์˜ path๋ฅผ "/feed/{feedNo}" ์ด๋ ‡๊ฒŒ ์ƒ์„ฑํ•œ๋‹ค๊ณ  ํ•˜๋ฉด feedNo์—๋Š” ๋™์ ์ธ ๊ฐ’๋“ค์ด ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด, name์€ path ์ฒ˜๋Ÿผ ์ƒ์„ฑํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.

name์€ ๋ช…๋ช…๋œ ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ์–ด๋–ค ํŽ˜์ด์ง€์ธ์ง€ ๋ผ์šฐํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ, path๋งŒ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋ผ์šฐํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด path ๊ฐ’์˜ contains๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜, ๋ฌด์–ธ๊ฐ€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์„œ ๋ผ์šฐํ„ฐ๋ฅผ ํ™•์ธํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค. ๋ฐ˜๋ฉด name์„ "feed" ๋ผ๊ณ  ์ง€์ •ํ•˜๊ฒŒ ๋˜๋ฉด ๋น„๊ต๋ฅผ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ณ„์†ํ•ด์„œ ์‚ฌ์šฉํ•ด ๋ณด๋ฉด์„œ ์ถ”๊ฐ€์ ์ธ ์„ค๋ช…์„ ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

์ถ”๊ฐ€๋กœ GoRouter.of(context)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ผ์šฐํŒ…์„ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

GoRouter.of(context).go(location);

builder VS pageBuilder

GoRoute์—์„œ ํŽ˜์ด์ง€๋ฅผ ์ •์˜ํ•  ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ธ builder์™€ pageBuilder์— ๋Œ€ํ•ด์„œ ๋น„๊ตํ•ด ๋ณด๋ฉด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

builder, pageBuilder๋Š” ๋ชจ๋‘ ๋™์ผํ•˜๊ฒŒ ๋ผ์šฐํŒ…์„ ์ง€์ •ํ•  ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

builder

builder๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ํŽ˜์ด์ง€๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์‹ฌํ”Œํ•˜๊ฒŒ Router๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ผ์šฐํŒ…์— ๋Œ€ํ•œ Transition์€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ BuildContext, GoRouterState๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, GoRouterState์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์—์„œ ํ•ด๋‹น ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณผ ๋•Œ์— ์ž์„ธํžˆ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ๋‹ค.

์ด๋ฏธ Flutter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์•ฑ์„ ๊ฐœ๋ฐœ ํ•˜์…จ๊ฑฐ๋‚˜, ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์•ฑ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด ๋ณด์‹  ๋ถ„๋“ค์€ ํŽ˜์ด์ง€๊ฐ€ ๋ผ์šฐํŒ…๋  ๋•Œ์— ํŽ˜์ด์ง€๊ฐ€ ์˜คํ”ˆ๋˜๋Š” ๋ฐฉ์‹์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค.
์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ Flutter์—์„œ๋Š” PageTransition์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, builder๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ณ„๋„๋กœ ์ง€์ •ํ•  ์ˆ˜ ์—†๊ณ , ํ”Œ๋žซํผ์— ๋งž๊ฒŒ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.

GoRoute(
	path: "/first",
	builder: (BuildContext context, GoRouterState state) => const FirstPage(),
),

pageBuilder

pageBuilder๋Š” builder ์ฒ˜๋Ÿผ ๋‹จ์ˆœํžˆ ์œ„์ ฏ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ MaterialPage ๋˜๋Š” CupertinoPage๋ฅผ ์ „๋‹ฌํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๋•Œ์— PageTransition์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

GoRoute(
	path: "/first",
	pageBuilder: (BuildContext context, GoRouterState state) => 
    			const MaterialPage(child: FirstPage()),
),

Transition

Transition์€ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ํŽ˜์ด์ง€๊ฐ€ ์ž‘๋™ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋ผ ์ดํ•ดํ•˜๋ฉด ์‰ฝ๋‹ค.

Android, iOS ํ”Œ๋žซํผ์€ ๋ณ„๋„์˜ ๋””์ž์ธ UI ์‹œ์Šคํ…œ์ด ์žˆ๋‹ค.
๊ฐ๊ฐ Material Design, Cupertino Design ์ด๋ผ๊ณ  ํ•œ๋‹ค.

๋””์ž์ธ UI ์‹œ์Šคํ…œ์— ๋”ฐ๋ผ ๋ฒ„ํŠผ, ์•ฑ๋ฐ”, ๋‹ค์ด์–ผ๋กœ๊ทธ ๋“ฑ์˜ ๋””์ž์ธ์ด ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ, ํŽ˜์ด์ง€์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜๋„ ๋‹ค๋ฅด๋‹ค.

Material ๋””์ž์ธ์€ ํŽ˜์ด์ง€๋ฅผ ๋ผ์šฐํŒ… ํ•  ๋•Œ์— ์ž‘์€ ํ™”๋ฉด์ด ์ปค์ง€๋ฉด์„œ ์ „์ฒด ํ™”๋ฉด์œผ๋กœ ๋ผ์šฐํŒ…๋˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ณ , iOS๋Š” ์˜ค๋ž˜์ „๋ถ€ํ„ฐ ์šฐ์ธก์—์„œ ์ขŒ์ธก์œผ๋กœ ์ด๋™ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.
Android๋Š” ๊ณผ๊ฑฐ์— ์•„๋ž˜์—์„œ ์œ„๋กœ ์˜ฌ๋ผ์˜ค๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‚ฌ์šฉํ•œ ์ ๋„ ์žˆ๋‹ค.

iOS Android

Flutter๋Š” ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ MaterialApp์œผ๋กœ ๋นŒ๋“œ๋ฅผ ํ•˜๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ธ๋ฐ, Material์„ ์‚ฌ์šฉ ํ•˜๋”๋ผ๋„ ๋ณ„๋„๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด PageTransition์€ ๊ฐ ํ”Œ๋žซํผ์˜ ๊ธฐ๋ณธ Transition์„ ์ ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

ํ”Œ๋žซํผ Transition์„ ๊ทธ๋ƒฅ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, ์œ„์—์„œ ์‚ดํŽด๋ณธ builder๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์‹ฌํ”Œํ•˜๊ฒŒ ๋ผ์šฐํŒ…์„ ์„ ์–ธํ•ด์ฃผ๋ฉด ๋˜์ง€๋งŒ ์›ํ•˜๋Š” Transition์„ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด
pageBuilder๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

PageTransition์—๋Š” ์–ด๋–ค ์ž‘๋™ ๋ฐฉ์‹๋“ค์ด ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

NoTransition
SlideTransition
FadeTransition
ScaleTransition

No Slide
Fade Scale

PageTransition์„ ์ปค์Šคํ…€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๋ฐฉ์‹์€ ์œ„์˜ 4๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

NoTransitionPage

NoTransition์€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. Page๊ฐ€ ๋ผ์šฐํŒ… ๋  ๋•Œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ผ์šฐํŒ…์„ ํ•˜๊ฑฐ๋‚˜ BottomNavigationBar๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ํ•ด๋‹น Transition์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

GoRoute(
	path: "/no",
	pageBuilder: (BuildContext context, GoRouterState state) =>
            const NoTransitionPage(child: NoPage()),
	),

CustomTransitionPage

Fade, Scale, Slide์™€ ๊ฐ™์€ Transition์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ, CustomTransition์„ ์‚ฌ์šฉํ•ด์„œ ๋งŒ๋“ค์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

CustomTranstionPage๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, transitionsBuilder๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์—์„œ Transtion์„ ์‚ฌ์šฉํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ๋ฅผ ์ปค์Šคํ…€ํ•˜๊ฒŒ ๊ตฌ์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

FadeTransition

GoRoute(
	path: "/fade",
	pageBuilder: (BuildContext context, GoRouterState state) => CustomTransitionPage(
          child: const FadePage(),
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) => FadeTransition(
            opacity: animation,
            child: child,
          ),
        ),
      ),

ScaleTransition

GoRoute(
	path: "/scale",
	pageBuilder: (BuildContext context, GoRouterState state) =>
            CustomTransitionPage(
          child: const ScalePage(),
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) => ScaleTransition(
            scale: animation,
            child: child,
          ),
        ),
      ),

SlideTranstion

GoRoute(
	path: "/slide",
	pageBuilder: (BuildContext context, GoRouterState state) =>
            CustomTransitionPage(
                child: const SlidePage(),
                transitionsBuilder: (
                  BuildContext context,
                  Animation<double> animation,
                  Animation<double> secondaryAnimation,
                  Widget child,
                ) => SlideTransition(
                      position: animation.drive(
                        Tween<Offset>(
                          begin: const Offset(1.25, 0),
                          end: Offset.zero,
                        ).chain(CurveTween(curve: Curves.easeIn)),
                      ),
                      child: child,
                    )),
      ),

CustomTransitionPage๋กœ ์›ํ•˜๋Š” Transition์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, Transtion์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด iOS์—์„œ ๋’ค๋กœ๊ฐ€๊ธฐ์— ์‚ฌ์šฉํ•˜๋Š” Gesture๋Š” ๋น„ํ™œ์„ฑํ™” ์ฒ˜๋ฆฌ๋˜๋‹ˆ ์ด ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

builder, pageBuilder ํ•จ๊ป˜ ์‚ฌ์šฉ์‹œ

๋งŒ์•ฝ์— builder์™€ pageBuilder๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ ?

builder, pageBuilder๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ ๋‘˜ ๋‹ค ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š๊ณ , pageBuilder๋ฅผ ์šฐ์„ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.

Go Vs Push

Go

๋ผ์šฐํŒ…์„ ํ•˜๋Š” ๋ช…๋ น์–ด์— ๋Œ€ํ•ด์„œ๋Š” ์•„์ง ์ž์„ธํžˆ ๋‹ค๋ฃจ์ง€ ์•Š์•˜์—ˆ๋‹ค.

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ผ์šฐํŒ…์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด go, push ์ด๋ ‡๊ฒŒ ์žˆ๋Š”๋ฐ, ๊ธฐ๋Šฅ๋“ค์˜ ์ฐจ์ด์ ์„ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

go, push ๋ชจ๋‘ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ์˜คํ”ˆํ•˜๋Š” ๊ฐœ๋…์€ ๋™์ผํ•œ๋ฐ, ๋ผ์šฐํŒ… ์Šคํƒ์—๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ฐจ์ด๋ฅผ ๋ณด์ธ๋‹ค.

๋จผ์ € go ๋ฐฉ์‹์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž. ๊ฐ„๋‹จํ•˜๊ฒŒ go๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , ํ•„์ˆ˜ ๊ฐ’์œผ๋กœ location, ์ฆ‰ path๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

context.go("/first");

์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๊ฐ€ ์˜คํ”ˆ๋˜๊ณ , ํŽ˜์ด์ง€๋ฅผ ๋‹ซ์•„๋ณด๋„๋ก ํ•˜์ž.

์–ด๋–ค์ผ์ด ์ผ์–ด๋‚ ๊นŒ ? ๋‹ซํžˆ์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. context.pop()์„ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ƒˆ๋กœ ์˜คํ”ˆํ•œ ํŽ˜์ด์ง€๋ฅผ ์™œ ๋‹ซ์„ ์ˆ˜ ์—†์„๊นŒ ? ์ด์œ ๋Š” ๋ฐ”๋กœ, ๋” ์ด์ƒ ๋‹ซ์„ ํŽ˜์ด์ง€๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

go ๋ผ์šฐํŒ… ๋ฐฉ์‹์€ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋กœ ๋Œ€์ฒดํ•˜์—ฌ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๊ธฐ๋ณธ ๊ฒฝ๋กœ๋ฅผ ์‹œ์ž‘์œผ๋กœ, ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ์—ด์–ด์ฃผ๊ณ , go๋ฅผ ์‚ฌ์šฉํ•ด ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ์˜คํ”ˆํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž.

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๋ผ์šฐํ„ฐ ์Šคํƒ์—๋Š” ์ˆœ์ฐจ์ ์œผ๋กœ "/", "/first", "/second" ์ด๋ ‡๊ฒŒ ์Šคํƒ์ด ์ฒ˜๋ฆฌ ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, go๋กœ "/second"๋ฅผ ์˜คํ”ˆํ•˜๋Š” ์ˆœ๊ฐ„ "/", "first" ์Šคํƒ์„ ๋Œ€์ฒดํ•˜๊ณ  "/second" ์Šคํƒ๋งŒ ๋‚จ๊ธฐ๊ฒŒ ๋œ๋‹ค.

๋ผ์šฐํ„ฐ ์Šคํƒ์— ์Œ“์ธ ๋ชจ๋“  ์Šคํƒ์„ ์ œ๊ฑฐํ•˜๊ณ  ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ์˜คํ”ˆํ•  ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๋ฐ”๋กœ go ์ด๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ go๋กœ ์˜คํ”ˆํ•˜๊ธฐ ์ „ ๋ผ์šฐํŠธ ์Šคํƒ์— dispose ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ์ถœ๋ ฅํ•ด ๋ณด๋ฉด์„œ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


void dispose() {
	super.dispose();
	print("FirstPage Dispose");
}

Push

์ด๋ฒˆ์—๋Š” push์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

push ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์šฐํ„ฐ์Šคํƒ์— ๋ผ์šฐํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ์ด๋™ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

context.push("/first);

์•„๋ž˜ ๊ธฐ๋Šฅ๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ์ด๋‹ค.

Navigator.of(context).push(route);

goNamed

์œ„์—์„œ ์‚ดํŽด๋ณธ go๋Š” location์œผ๋กœ ์„ค์ •ํ•œ path ๊ฐ’์„ ๋„ฃ์–ด์•ผ ํ•˜์ง€๋งŒ, named๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด goNamed๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

context.go("first");

pushNamed

์ด๋ฒˆ์—” push์˜ named ๋ฐฉ๋ฒ•์ด๋‹ค.

context.pushNamed("first");

pushReplacement

์ด๋ฒˆ์—” Replacement๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์ž. ์šฐ์„  ๋ชจ๋“  ๋ผ์šฐํŠธ ์Šคํƒ์„ ๋Œ€์ฒดํ•˜๋Š” go๋Š” ๋‹น์—ฐํžˆ Replacement ๊ฐœ๋…์ด ์—†๊ณ , push์—๋งŒ ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

Replacement๋Š” ๋Œ€์ฒดํ•˜์—ฌ ์ด๋™ํ•˜๋Š” ๊ฐœ๋…์ธ๋ฐ, ์–ผํ•๋ณด๋ฉด go์™€ ๋™์ผํ•ด ๋ณด์ด์ง€๋งŒ Replacement๋Š” ํ˜„์žฌ ๋ผ์šฐํŠธ์Šคํƒ๋งŒ ์ƒˆ๋กœ์šด ๋ผ์šฐํ„ฐ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

context.pushReplacement("/second");
Push PushReplacement

pushReplacementNamed

pushReplacement์˜ named ๋ฐฉ์‹์ด๋‹ค.

context.pushReplacementNamed("/second");

์ด๋ฒˆ์—๋Š” go_router ํŒจํ‚ค์ง€์˜ ํŽธํ•œ ๋””๋ฒ„๊น… ๊ธฐ๋Šฅ์ธ Observer์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

Bloc ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด ๋ณด์‹  ๋ถ„๋“ค์€ Bloc์ด ๊ฐ€์ง€๋Š” ObserverPattern์— ๋Œ€ํ•ด์„œ ์ข‹์€ ๊ธฐ๋Šฅ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค.

go_router์—์„œ๋„ ๋™์ผํ•œ Observer๋ฅผ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

๋จผ์ € Observer๋ฅผ ๊ตฌ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

NavigatorObserver๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , didPush, didPop, didRemove, didReplace๋ฅผ ์žฌ์ •์˜ ํ•˜์—ฌ ์›ํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋„ฃ์„ ์ˆ˜๋„ ์žˆ๊ณ  ๋””๋ฒ„๊น… ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•ด ๋ณผ ์ˆ˜๋„ ์žˆ๋‹ค.

class RouterObserver extends NavigatorObserver {
  
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print("DidPush: $route");
  }

  
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print("DidPop: $route");
  }

  
  void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print("DidRemove: $route");
  }

  
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    print("DidReplace: $newRoute");
  }
}

RouterObserver ๊ฐ์ฒด๋ฅผ GoRouter์˜ observers ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

observers ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฐฐ์—ด๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ NavigatorObserver๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

static GoRouter router = GoRouter(
    initialLocation: "/",
    observers: [RouterObserver()],
    routes: [
		...
   ],
);

์ด์ œ Observer๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์œผ๋‹ˆ, ์œ„์—์„œ ์‚ดํŽด๋ณธ go ๊ธฐ๋Šฅ๊ณผ push ๊ธฐ๋Šฅ์˜ ์ฐจ์ด๋ฅผ ๋” ์‰ฝ๊ฒŒ ๋กœ๊ทธ๋กœ ์ถœ๋ ฅํ•ด ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

Object

์ด์–ด์„œ ๋ผ์šฐํ„ฐ ๊ธฐ๋Šฅ์˜ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Flutter๋Š” ์œ„์ ฏ๊ฐ„ Constructor๋ผ๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ณ , ๋‹น์—ฐํžˆ go_router์—์„œ๋„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

Person์ด๋ผ๋Š” ํŽ˜์ด์ง€๋กœ name, age, email์„ ๋„˜๊ฒจ์ฃผ๋„๋ก ํ•˜์ž.

๋จผ์ € Person ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

class PersonPage extends StatelessWidget {
  final String name;
  final int age;
  final String email;
  const PersonPage({
    super.key,
    required this.name,
    required this.age,
    required this.email,
  });
  
  ...
}

์ด์ œ GoRoute๋ฅผ ์ •์˜ํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, go_router ํŒจํ‚ค์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฅผ GoRouterState ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ์ „๋‹ฌ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

GoRouteState ๊ฐ์ฒด์˜ extra๋Š” Object? ํƒ€์ž…์„ ์ „๋‹ฌ ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๊ธฐ์— ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

GoRoute(
	path: "/person",
	name: "person",
	builder: (BuildContext context, GoRouterState state) {
		return PersonPage(
              name: (state.extra as Map<String, dynamic>)["name"],
              age: (state.extra as Map<String, dynamic>)["age"],
              email: (state.extra as Map<String, dynamic>)["email"],
            );
	}
),

์ด์ œ ๋ผ์šฐํ„ฐ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ์— extra์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ดค๋‹ค.

context.push("/person",
	extra: {
		"name": name,
		"age": age,
		"email": email,
});

Map ํƒ€์ž…์ด ์•„๋‹Œ Object๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๊ธฐ ๋•Œ๋ฌธ์—, Person ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

class Person {
  final String name;
  final int age;
  final String email;

  const Person({
    required this.name,
    required this.age,
    required this.email,
  });
}

extra๋ฅผ Person ๊ฐ์ฒด๋กœ ํƒ€์ž… ์บ์ŠคํŠธํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

GoRoute(
	path: "/person",
	name: "person",
	builder: (BuildContext context, GoRouterState state) {
            return PersonPage(
              person: state.extra as Person,
            );
	}
),

Path Parameter

์ด๋ฒˆ์—” path์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

path์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ด์œ ๋Š” ๋™์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฝ๋กœ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

๋งŒ์•ฝ์— SNS ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ํ”ผ๋“œ๋ฅผ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ๋•Œ์— ํ•ด๋‹น ํ”ผ๋“œ์˜ ๊ณ ์œ ํ•œ ํ”ผ๋“œ ๋ฒˆํ˜ธ๋ฅผ ์•Œ๊ณ  ์žˆ์–ด์•ผ ๋ฐ์ดํ„ฐ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•  ๊ฒƒ์ด๋‹ค. ํ”ผ๋“œ ๋ฒˆํ˜ธ๋ฅผ path ๊ฒฝ๋กœ์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ์— ์‚ฌ์šฉ๋˜๋ฉฐ, ์›น์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

FeedPage๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ํ”ผ๋“œ์˜ ๋ฒˆํ˜ธ๋งŒ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋ผ์šฐํ„ฐ๋ฅผ ์ •์˜ํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

path๋ฅผ ์ƒ์„ฑ์‹œ /:feedNo๋ผ๊ณ  ํ•ด์ค€๋‹ค๋ฉด / ๋‹ค์Œ์— ์˜ค๋Š” ๊ฐ’์„ GoRouterState์˜ pathParameters ์ •๋ณด์— ๋‹ด๊ฒจ์ ธ ์ œ๊ณต๋œ๋‹ค.

ํ•ด๋‹น ๊ฒฝ๋กœ์— ์˜ค๋Š” ๊ฐ’์€ ์ •์˜ํ•ด์ค€ feedNo๋กœ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

GoRoute(
	path: "/feed/:feedNo",
	builder: (BuildContext context, GoRouterState state) => 
    	FeedPage(feedNo: int.parse(state.pathParameters["feedNo"]!),
	),
),

๋‹น์—ฐํžˆ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ์—” ์‚ฌ์šฉ์ž์˜ ๊ณ ์œ  ID ๊ฐ’๋„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด๋ณด์ž.

์ด๋Ÿฐ ๋ฐฉ๋ฒ•์œผ๋กœ ์›ํ•˜๋Š” path ๊ฒฝ๋กœ์—์„œ ๋™์  ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

GoRoute(
	path: "/feed/:feedNo/:uid",
	builder: (BuildContext context, GoRouterState state) => 
    	FeedPage(
        	feedNo: int.parse(state.pathParameters["feedNo"]!
            uid: state.pathParameters["uid"]!,
      	),
	),
),

์ƒ์„ฑํ•œ path ๊ฒฝ๋กœ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ „๋‹ฌ ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋‹ˆ, ๋ฐ˜๋“œ์‹œ ํ•„์ˆ˜๋กœ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Query Parameter

์ด๋ฒˆ์—๋Š” Query Parameter์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

์œ„์—์„œ ์‚ดํŽด๋ณธ Path Parameter๋Š” ๋ฐ˜๋“œ์‹œ ํ•„์ˆ˜์ ์œผ๋กœ path์— ๊ฐ’์„ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ฐ˜๋ฉด, Query Parameter๋กœ ์ •์˜๋œ ๊ฐ’์€ ์˜ต์…”๋„ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฒ€์ƒ‰ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  Optional Parameter๋กœ keyword๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋ณด์ž.

keyword๋Š” Nullable ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌ ๋ฐ›์œผ๋ฉด ๋˜๊ณ , GoRouterState์˜ uri ์ •๋ณด์— ๋‹ด๊ธด queryParameters๋ฅผ ์‚ฌ์šฉํ•ด keyword๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

GoRoute(
	name: "search",
	path: "/search",
	builder: (BuildContext context, GoRouterState state) => SearchPage(
	keyword: state.uri.queryParameters["keyword"],
	)
),

Query Parameter๋ฅผ ๋ผ์šฐํŒ…ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋จผ์ € named๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

pushNamed ๋˜๋Š” goNamed์—๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ queryParameters๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์—ฌ๊ธฐ์— keyword๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

context.pushNamed("search", queryParameters: {
	"keyword": "๊ฒ€์ƒ‰์–ด",
});

์ด๋ฒˆ์—๋Š” named๊ฐ€ ์•„๋‹Œ path๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. path ๊ฒฝ๋กœ์— ์˜ต์…”๋„ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ ? annotation์„ ์‚ฌ์šฉํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

context.push("/search?keyword=๊ฒ€์ƒ‰์–ด");

Callback

์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ๋ผ์šฐํŒ…ํ•  ๋•Œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ดค์œผ๋‹ˆ, ์ด๋ฒˆ์—” ๋ฐ˜๋Œ€๋กœ ํŽ˜์ด์ง€๋ฅผ ๋‹ซ์„ ๋•Œ ๋ถ€๋ชจ ์œ„์ ฏ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

pop() ์ด๋ฒคํŠธ์— ๊ฒฐ๊ณผ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด๋ฏธ ๊ธฐ์กด ๋ผ์šฐํŒ… ๋ฐฉ์‹์—๋„ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ๋“ค์ด๋‹ค. go_router์—์„œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

pop() ์ด๋ฒคํŠธ ์•ˆ์— ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

context.pop(true);

๋ผ์šฐํŒ… ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ์ฝœ๋ฐฑ์— ๋Œ€ํ•ด ์ˆ˜์‹ ์„ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

context.push("/test").then((value) {
	print(value);
});

// flutter: true

Map ํƒ€์ž…์„ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

context.pop({
	"name": "Tyger",
	"age": 100,
	"email": "boglbbogl@gmail.com",
});
context.push("/test").then((value) {
	print(value);
});

// flutter: {name: Tyger, age: 100, email: boglbbogl@gmail.com}

Object๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•ด ๋ณด๋„๋ก ํ•˜์ž.

class Person {
  final String name;
  final int age;
  final String email;
  final DateTime birthday;

  const Person({
    required this.name,
    required this.age,
    required this.email,
    required this.birthday,
  });
}

๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

Person person = Person(
	name: "Tyger",
	age: 100,
	email: "boglbbogl@gmail.com",
	birthday: DateTime(2000, 01, 01),
);
context.pop(person);
context.push("/test").then((value) {
	print(value);
});

// flutter: Person(name: Tyger, age: 100, email: boglbbogl@gmail.com, birthday: 2000-01-01 00:00:00.000)

๋ณ€์ˆ˜, Map, Object ์™ธ์—๋„ ๋ฐฐ์—ด์„ ์ฝœ๋ฐฑ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ถ”๊ฐ€๋กœ pushReplacement๋Š” ๋ผ์šฐํŒ…์„ ์š”์ฒญํ•œ ํŽ˜์ด์ง€์˜ ์Šคํƒ์ด ์‚ฌ๋ผ์ ธ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ์ˆ˜ ์—†์œผ๋‹ˆ, ์ฝœ๋ฐฑ์— ๋Œ€ํ•œ ๋ผ์šฐํŠธ ์Šคํƒ์„ ์ž˜ ๊ณ ๋ คํ•ด์„œ ์„ค๊ฒŒ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

Redirect

์ด๋ฒˆ์—๋Š” Redirect ๋ผ์šฐํŒ…์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

GoRouter๋Š” ๋“ฑ๋ก๋œ ๋ผ์šฐํ„ฐ๋ฅผ ๋™์ž‘์‹œํ‚ฌ ๋•Œ์— ์›ํ•˜๋Š” ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋˜์–ด์žˆ๋‹ค.

Redirect ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ์ถฉ๋ถ„ํžˆ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Redirect๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋ฉด, ๋ผ์šฐํ„ฐ ๋“ฑ๋ก ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ๋ฅผ ์ข€ ๋” ์ˆ˜์›”ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

Redirect ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค. Redirectํ•˜๊ณ  ์‹ถ์€ path๋ฅผ ๋“ฑ๋กํ•ด ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

FirstPage, RedirectPage๋ฅผ ๋ผ์šฐํ„ฐ์— ๋“ฑ๋กํ•˜๋„๋ก ํ•˜์ž.

GoRoute(
	path: "/first",
	builder: (BuildContext context, GoRouterState state) =>  const FirstPage(),
),
GoRoute(
	path: "/redirect",
	builder: (BuildContext context, GoRouterState state) =>  const RedirctPage(),
),

FirstPage ๋ผ์šฐํ„ฐ์— redirect ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋„๋ก ํ•˜์ž.

๊ฐ„๋‹จํ•˜๊ฒŒ path๋งŒ ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

GoRoute(
	path: "/first",
	builder: (BuildContext context, GoRouterState state) =>  const FirstPage(),
    redirect: (BuildContext context, GoRouterState state) {
          return "/redirect";
        },
),

์ด์ œ push๋ฅผ ํ•ด์ฃผ๊ฒŒ ๋˜๋ฉด, FirstPage๋กœ ๋ผ์šฐํŒ…์ด ๋˜์ง€ ์•Š๊ณ , Redirect ํŽ˜์ด์ง€๋กœ ๋ผ์šฐํŒ…์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

context.push("/first");

redirect ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋“ฑ๋ก๋œ ๊ฒฝ๋กœ๋ฅผ ๋ผ์šฐํŒ…ํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋ฒˆ์—๋Š” ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜์—ฌ Redirect ๋ผ์šฐํŒ…์„ ์ง„ํ–‰ํ•ด ๋ณด๋„๋ก ํ•˜์ž.

์›”์„ ๋ฐ›์•„์™€์„œ ๋ด„์ด๋ฉด SpringPage()๋กœ Redirect ํ•˜๊ณ , ์—ฌ๋ฆ„์ด๋ฉด SummerPage()๋กœ, ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ๋Š” Redirect๋ฅผ ํ•˜์ง€ ์•Š๋„๋ก ํ•ด๋ณด์ž.

MontlyPage ๋ผ์šฐํ„ฐ๋ฅผ ๋“ฑ๋กํ•ด ์ฃผ๊ณ , path๋กœ ํ˜„์žฌ ํ„ฐ์น˜๋œ ์›”์„ ๋ฐ›์•„์˜ค๋„๋ก ํ•˜์ž.

GoRoute(
	path: "/montly/:month",
	builder: (BuildContext context, GoRouterState state) => MontlyPage(
          title: state.pathParameters["month"]!,
        ),
),

Spring, Summer ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๋ผ์šฐํ„ฐ๋„ ๋“ฑ๋กํ•ด ๋‘์ž.

GoRoute(
	path: "/summer/:content",
	builder: (BuildContext context, GoRouterState state) => SummerPage(
		content: state.pathParameters["content"]!,
)),
GoRoute(
	path: "/spring/:content",
	builder: (BuildContext context, GoRouterState state) => SpringPage(
		content: state.pathParameters["content"]!,
)),

redirect ์กฐ๊ฑด์„ MontlyPage์— ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

redirect: (BuildContext context, GoRouterState state) {
	switch (state.pathParameters["month"]!) {
		case "Mar" || "Apr" || "May":
			return "/spring/${state.pathParameters["month"]}";
		case "Jun" || "Jul" || "Aug":
			return "/summer/${state.pathParameters["month"]}";
		default:
			return null;
          }
        },
Redirect Redirect X

Multiple Routing

๋‹ค์ค‘ ๋ผ์šฐํŒ…์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

๋‹ค์ค‘ ๋ผ์šฐํŒ…์€ ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€๋ฅผ ๋ผ์šฐํŒ…ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์„œ๋ธŒ ์Šคํƒ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ง€์ •ํ•œ ํŽ˜์ด์ง€๋“ค์„ ๋ผ์šฐํŒ… ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

๋งŒ์•ฝ์— FirstPage(), SecondPage() ์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ ํŽ˜์ด์ง€๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์˜คํ”ˆํ•˜๋ฉด์„œ ์ด๋™ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด์ž.

๋‹ค์ค‘ ๋ผ์šฐํŒ…์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ ์—ฐ์†์œผ๋กœ ๋ผ์šฐํŒ…์„ ์ง„ํ–‰ํ•  ๊ฒƒ์ด๋‹ค.

context.push("/first");
context.push("/second");

go_router๋Š” ๋‹ค์ค‘ ๋ผ์šฐํŒ…์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ฝ”๋“œ๋ฅผ ์—ฐ์†์ ์œผ๋กœ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด path์— ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํŽ˜์ด์ง€๋“ค์„ ๋ผ์šฐํŒ… ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๋จผ์ € FirstPage()์— ๋Œ€ํ•œ ๋ผ์šฐํŠธ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ์ž.

GoRoute(
	path: "/first",
	builder: (BuildContext context, GoRouterState state) =>
            const FirstPage(),
),

SecondPage()์— ๋Œ€ํ•œ ๋ผ์šฐํŠธ๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ธ๋ฐ, ์ด ๋•Œ์— SecondPage() ํ˜ธ์ถœ์‹œ FirstPage()๋ฅผ ์˜คํ”ˆํ•˜๊ณ  SecondPage()๋ฅผ ์—ด์–ด์ค„ ์ˆ˜ ์žˆ๋„๋ก ํ•  ๊ฒƒ์ด๋‹ค.

GoRoute์—๋Š” routes๋ฅผ ๋ฐฐ์—ด๋กœ subRoutes๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์ค‘ ํŽ˜์ด์ง€๋ฅผ ๋ผ์šฐํŒ…ํ•˜๋Š” ๊ฒƒ์€ push๋กœ๋Š” ์ง„ํ–‰ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, go๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

์œ„์—์„œ go์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ดค์„ ๋•Œ์—, go๋Š” ํŽ˜์ด์ง€๋ฅผ ๋Œ€์ฒดํ•˜๊ณ  ์ด๋™ํ•œ๋‹ค๊ณ  ํ•˜์˜€๋‹ค.
๋งŒ์ผ FirstPage()๋ฅผ GoRoute๋กœ ๋“ฑ๋กํ•˜๊ณ  subRoute๋กœ SecondPage()๋ฅผ ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด, ์•ฑ์˜ ์ตœ์ƒ์œ„ ๋ผ์šฐํŠธ๊ฐ€ FirstPage()๋กœ ๋Œ€์ฒด๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค์‹œ ํ™ˆ์œผ๋กœ ๋Œ์•„์˜ค๊ธธ ์›ํ•œ๋‹ค๋ฉด, initialRoute์˜ subRoute๋กœ ๋“ฑ๋กํ•ด์•ผ ํ•œ๋‹ค.

GoRoute(
	path: "/",
	builder: (BuildContext context, GoRouterState state) => const HomePage(),
	routes: [
		GoRoute(
            path: "first",
            builder: (BuildContext context, GoRouterState state) =>
                const FirstPage(),
            routes: [
              GoRoute(
                  path: "second",
                  builder: (BuildContext context, GoRouterState state) =>
                      const SecondPage()),
            ],
          ),
        ],
      ),

subRoute๋ฅผ ๋“ฑ๋ก ํ•˜์˜€์œผ๋‹ˆ, ์ด์ œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

๋จผ์ €, subRoute๋กœ ๋“ฑ๋กํ•œ FirstPage(), SecondPage()๋ฅผ ์˜คํ”ˆํ•˜๊ณ  ๊ฐ€๊ณ  ์‹ถ๋‹ค๋ฉด go๋ฅผ ์‚ฌ์šฉํ•ด path๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

๋ผ์šฐํŒ…๋œ ํŽ˜์ด์ง€๋ฅผ ๋ณด๋ฉด SecondPage()๊ฐ€ ๋ณด์ด๊ณ , pop()์„ ํ•˜๊ฒŒ ๋˜๋ฉด, FirstPage()๊ฐ€ ๋ณด์ด๊ฒŒ ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ ํ•œ๋ฒˆ๋” pop()์„ ํ•˜๊ฒŒ ๋˜๋ฉด, subRoute์˜ ์ƒ์œ„ Route์ธ "/" ํ•ด๋‹น ๊ฒฝ๋กœ๋กœ ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

context.go("/first/second");

push๋ฅผ ํ•ด์ฃผ๊ฒŒ ๋˜๋ฉด, Second() ํŽ˜์ด์ง€๋งŒ ์˜คํ”ˆ๋œ๋‹ค.

FirstPage()๋งŒ ์˜คํ”ˆํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

context.push("/first");

SecondPage()๋งŒ ์˜คํ”ˆํ•˜๊ณ  ์‹ถ์„ ๋•Œ์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ๋จผ์ €, push๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

context.push("/first/second");

๋‹ค์Œ์€ "/second" ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ, ์ƒˆ๋กœ์šด Route๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

GoRoute(
	path: "/second",
	builder: (BuildContext context, GoRouterState state) =>
            const SecondPage(),
      ),
context.push("/second");

๋ฐ์ดํ„ฐ ์ „๋‹ฌ๋„ ๊ธฐ์กด ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•˜๋‹ค.

FirstPage()์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž.

 GoRoute(
	path: "first/:path",
	builder: (BuildContext context, GoRouterState state) => FirstPage(
		path: state.pathParameters["path"]!,
	),
	routes: [
		GoRoute(
			path: "second",
			builder: (BuildContext context, GoRouterState state) =>
                      const SecondPage()),
	],
),

FirstPage -> SecondPage

context.go("/first/go/second");

FirstPage

context.push("first/push");

Error

์ด์–ด์„œ Error์— ๊ด€ํ•œ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด์ž.

Error๋ฅผ ๋ฐœ์ƒํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋“ฑ๋ก๋˜์ง€ ์•Š์€ path๋กœ ๋ผ์šฐํŒ…์„ ํ•ด๋ณด๋ฉด ๋œ๋‹ค.

context.push("/error");

๋ผ์šฐํ„ฐ๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

go_router ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์—๋Ÿฌ์— ๋Œ€ํ•œ ๋ณ„๋„์˜ ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์—๋Ÿฌ๋„ ์œ„์—์„œ ์‚ดํŽด๋ณธ Redirect ์ฒ˜๋Ÿผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

errorBuilder, errorPageBuilder ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

errorBuilder๋ฅผ ์‚ฌ์šฉํ•ด ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋“ฑ๋กํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

์—๋Ÿฌ๋Š” GoRouter ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋“ฑ๋ก์ด ๋œ๋‹ค.

errorBuilder

static GoRouter router = GoRouter(
    initialLocation: "/",
    errorBuilder: (BuildContext context, GoRouterState state) => ErrorPage(
      path: state.matchedLocation,
    ),
 	...
);

errorPageBuilder

static GoRouter router = GoRouter(
    initialLocation: "/",
    errorPageBuilder: (BuildContext context, GoRouterState state) =>
        NoTransitionPage(child: ErrorPage(path: state.matchedLocation)),
 	...
);

Error์— ๋Œ€ํ•œ UI๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ถ”๊ฐ€๋กœ ๋ผ์šฐํ„ฐ builder์™€๋Š” ๋‹ค๋ฅด๊ฒŒ, error๋Š” builder ๋˜๋Š” pageBuilder ํ•˜๋‚˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ , ๋‘˜ ๋‹ค ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋“ฑ๋กํ•˜์ง€ ์•Š์€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ path๊ฐ€ ์ž˜ ๋ชป๋œ ๊ฒฝ์šฐ์—๋„ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ๋ผ์šฐํŒ…์ด ๋œ๋‹ค.

GoRoute(
	path: "/test/:id",
	builder: (BuildContext context, GoRouterState state) => const TestPage(),
),

id ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

context.push("/test");

BottomNavigationBar

go_router๋ฅผ ์‚ฌ์šฉํ•ด์„œ BottomNavigationBar๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

BottomNavigationBar ๊ธฐ๋Šฅ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ์ •๋ง ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•๋“ค์ด ์กด์žฌํ•œ๋‹ค. go_router์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ์ด๋“ค ์ค‘ ํ•œ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ ํ™”์— ๋งž๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ ์šฉํ•ด ๋ณด์‹œ๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

BottomNavigationBar ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” shellRoute๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

StatefulShellRoute.indexedStack ์ด ๋ฐ”๋กœ IndexedStack์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ„ํŽธํ•˜๊ฒŒ BottomNavigationBar๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ ์ด๋‹ค.

branches ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•„์ˆ˜๋กœ ๋“ฑ๋กํ•ด์•ผ ํ•œ๋‹ค.

builder๋ฅผ ์‚ฌ์šฉํ•ด BottomNavigationBar๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด ๋œ๋‹ค.

StatefulShellRoute.indexedStack(
	branches: [],
	builder: (BuildContext context, GoRouterState state,
                StatefulNavigationShell navigationShell) => Scaffold(),
),

BottomNavigationBar๋ฅผ 3๊ฐœ์˜ ํƒญ์œผ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์ƒ์„ฑํ•˜์˜€๋‹ค.

body ๋ถ€๋ถ„์€ StatefulNavigationShell ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋˜๊ณ , currentIndex๋„ StatefulNavigationShell ๊ฐ์ฒด์— ํ˜„์žฌ์˜ currentIndex ์ •๋ณด๊ฐ€ ์žˆ๋‹ค.

StatefulNavigationShell ๊ฐ์ฒด์— BottomNavigationBar๋ฅผ ์ƒ์„ฑํ•  ๋•Œ์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

StatefulShellRoute.indexedStack(
	branches: [],
	builder: (BuildContext context, GoRouterState state,
                StatefulNavigationShell navigationShell) => Scaffold(
          body: navigationShell,
          bottomNavigationBar: BottomNavigationBar(
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(icon: Icon(Icons.home), label: "A"),
              BottomNavigationBarItem(icon: Icon(Icons.settings), label: "B"),
              BottomNavigationBarItem(icon: Icon(Icons.account_circle), label: "C"),
            ],
            currentIndex: navigationShell.currentIndex,
            onTap: (int index) => null,
          ),
        ),,
),

StatefulNavigationShell ๊ฐ์ฒด์˜ goBranch()๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํƒญ์„ ๋ณ€๊ฒฝํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

onTap: (int index) => navigationShell.goBranch(index),

branches์— BottomNavigationBar ๋ฐ”๋””์— ํ•ด๋‹นํ•˜๋Š” ์Šคํฌ๋ฆฐ๋“ค์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด ๋•Œ์— StatefulShellBranch ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋˜๊ณ , routes์—๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ GoRoute๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

subRoutes ๋“ฑ๋ก ์—ญ์‹œ๋„ ๊ธฐ์กด์˜ ์‚ฌ์šฉํ•˜๋˜ ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•˜๋‹ค.

branches: [
	StatefulShellBranch(
		routes: [
			GoRoute(
				path: "/screenA",
				builder: (context, state) => const AScreen(),
			),
		],
	),
	StatefulShellBranch(
		routes: [
			GoRoute(
				path: "/screenB",
				builder: (context, state) => const BScreen(),
			),
		],
	),
    StatefulShellBranch(
		routes: [
			GoRoute(
				path: "/screenC",
				builder: (context, state) => const CScreen(),
			),
		],
	),
],

์•ฑ์ด ์‹œ์ž‘๋˜๊ณ  initialRoutes๊ฐ€ BottomNavigationBar๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํƒญ์˜ ๋ฐ”๋”” ๋ถ€๋ถ„์˜ path๋กœ ์ง€์ •ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

initialLocation: "/screenA",

subRoutes๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, BottomNavigationBar ์œ„์—์„œ ๋ผ์šฐํŒ…์ด ๋˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€๊ฐ€ ์ „ํ™˜ ๋˜๋”๋ผ๋„ BottomNavigationBar๊ฐ€ ๋‚จ์•„ ์žˆ์œผ๋‹ˆ, ์ด ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•ด์„œ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋œ๋‹ค.

GoRouter

routes: [
      GoRoute(
        path: "/subScreenC",
        builder: (context, state) => const CSubScreen(
          isSub: false,
        ),
      ),
],

StatefulShellRouter

StatefulShellBranch(
	routes: [
		GoRoute(
			path: "/screenC",
			builder: (context, state) => const CScreen(),
				routes: [
					GoRoute(
						path: "subScreenC",
						builder: (context, state) => const CSubScreen(),
				)
	 		])
		],
),

๋งˆ๋ฌด๋ฆฌ

์ง€๊ธˆ๊นŒ์ง€ go_router๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์šฐํ„ฐ ๋“ฑ๋ก ๋ถ€ํ„ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ๋ฐ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์•˜๋‹ค.

๋ผ์šฐํ„ฐ๋Š” Flutter์˜ ๊ธฐ๋ณธ Navigator๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋„ ์–ผ๋งˆ๋“ ์ง€ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— go_router ์‚ฌ์šฉ์ด ํ•„์ˆ˜์ ์ธ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ์— ๋งž๋Š” ๋ผ์šฐํ„ฐ๋ฅผ ์„ ํƒํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค !

๊ถ๊ธˆํ•˜์‹  ๋ถ€๋ถ„์ด ์žˆ๊ฑฐ๋‚˜ ์ถ”๊ฐ€์ ์œผ๋กœ go_router์— ๋Œ€ํ•ด์„œ ์•Œ๊ณ  ์‹ถ์€ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์„ธ์š” ๐Ÿ’ฌ

profile
Flutter Developer

0๊ฐœ์˜ ๋Œ“๊ธ€