GoRouter

Clean Code Big Poo·2023년 4월 13일
1

Flutter

목록 보기
26/38
post-thumbnail

Overview

flutter 개발진이 홍보하는 goRouter

goRouter는 url path 방식으로 라우팅을 지원하는 패키지이다. 무려 공식 패키지이니, 마음놓고 사용할 수 있겠다.

install

이 곳에서 install을 진행한다.

Usage

app_router 정의

다음은 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;
      }
    },
  );
}

redirect

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));

   
  }
}

MaterialApp.router

go router를 사용하기 위해 MaterialApp을 MaterialApp.router로 바꾸어 정의한다.


  Widget 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,              
            );
          }),
        );
      },
    );
  }

이제 goRouter를 사용하여 페이지 간 이동을 해보자.

//아래의 두 코드는 같은 의미이다.
GoRouter.of(context).go('/home');
context.go('/home');
//아래의 두 코드는 같은 의미이다.
GoRouter.of(context).push('/home');
context.push('/home');

go와 push의 차이

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

ShellRoute

bottom navigation을 사용할 때 ShellRoute를 사용한다. 아직 ShellRoute는 사용해 본적이 없어... 나중에 정리하러 들어오겠음!

참고

Get Started
using go route 6

1개의 댓글

comment-user-thumbnail
2023년 12월 12일

질문이 하나 있는데요
죄송하지만 보통 처음 화면은 스플래시 화면먼저 띄우지 않나요??
적힌거를 보면 홈화면을 가장 먼저 띄우는 것 처럼 되어잇는데.....
제가 이해를 잘못한건지..ㅠㅠㅠㅠㅠ알려주시면 안될까요?

답글 달기