통조림

[Flutter]GoRouter Redirection 본문

Software/Flutter

[Flutter]GoRouter Redirection

고랭지참치 2024. 4. 2. 18:22

Flutter 공식 개발팀에서 지원하는 라우팅 패키지인 go_router는 다양한 기능을 제공한다. 그 중에서도 가장 유용하게 사용할 수 있는 기능인 redirection 사용방법을 기록해놓고자 한다.

전체 작성 코드는 깃허브에 올려놨다.

https://github.com/KoreanTuna/go_router_study

...
redirect라는 개념은 go_router에서만 사용되는 것은 아니고, 웹을 개발하는 react나 여러 백앤드 프로그래밍에서 사용되고 있는 개념이다. 사용자가 특정 URL에 접근하려 할 때, 자동으로 사용자의 권한 혹은 상태를 확인하여 해당 URL이 아닌 미리 설정된 URL로 이동시키는 기능이다.
참고한 사이트 [https://www.semrush.com/blog/redirects/]

go_router또한 Url 베이스로 라우트를 처리하기 때문에 동일한 컨셉을 가져온 것으로 생각된다.

GoRouter 클래스 선언하기

다음은 Riverpod을 사용하여 go_router를 선언한 가장 기본적인 코드다.
initial Location route와 GlobalKey타입의 navigatorKey를 파라미터로 전달하고, routes에 GoRoute() 로 구현된 스크린 단위를 전달하면 된다.

part 'router.g.dart';

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@riverpod
GoRouter router(RouterRef ref,
    [String initialLocation = BottomNavScreen.routeName]) {
  final GoRouter goRouter = GoRouter(
    initialLocation: '/$initialLocation',
    navigatorKey: navigatorKey,
    routes: <RouteBase>[
      GoRoute(
        path: '/${SplashScreen.routeName}',
        name: SplashScreen.routeName,
        builder: (BuildContext context, GoRouterState state) {
          return SplashScreen();
        },
      ),
    ],
  );

  return goRouter;
}

 

Redirection 및 refreshListenable 파라미터 추가

다음으로는 Listenable 타입의 오브젝트를 refreshListenable 파라미터에 전달하고, 해당 클래스가 notiify를 할 때마다 실행되는 redirection 함수를 구현하면 된다.

refreshListenable: authNotifier

Material 라이브러리에서 제공해주는 ChangeNotifier를 상속하는 클래스를 선언한다.
나는 프로젝트에서 사용자 AuthState를 Riverpod Provider를 통해 관리해주고 있었기 때문에, Ref를 매개변수로 받는 생성자를 만들어, ref.listen()으로 userStateProvider의 State가 업데이트 되는 것을 감지할 수 있도록 만들었다.

  final AuthNotifier authNotifier = AuthNotifier(ref);
import 'package:flutter/material.dart';

class AuthNotifier extends ChangeNotifier {
  final Ref _ref;
  AuthNotifier(this._ref) {
    _ref.listen<UserAuthState>(userStateProvider, (previous, next) {
      logger.w('User State Changed : $next');
      notifyListeners();
    });
  }
}

...

ref.listen은 바라보고 있는 provider State의 값이 업데이트 될 때마다 특정 로직을 수행시킬 수 있다.
여기서는 notifyListeners() 메소드를 실행시키도록 해서, 업데이트가 될 때마다 go_router에게 redirect를 요청할 수 있도록 만들었다.

그리고 아래 코드처럼 refreshListenable 파라미터에 AuthNotifier 객체를 전달했다.

...

@riverpod
GoRouter router(RouterRef ref) {
  final AuthNotifier authNotifier = AuthNotifier(ref);

  final GoRouter goRouter = GoRouter(
    refreshListenable: authNotifier,
    
    ...

 

redirect 함수 구현

이제 authNotifier가 notifyListener()를 실행해서 auth가 변경될때마다 실행될 redirect 함수를 구현한다.
사용자를 rerirect시킬 라우트 path를 리턴해주면 되고, 리턴해줄 값이 없다면 null을 리턴해주면 된다.
redirect는 context와 state를 제공한다.

state는 현재 유저가 위치한 route의 url과 pathParameter, pageKey, extra 값들을 제공해주기 때문에, 현재 위치에 따라 분기를 나눠 로직을 태울 수도 있다.

나는 아래와 같이 AuthState의 상태가 authenticated가 아니라면 Splash화면으로 이동시키도록 작성했다.

...
@riverpod
GoRouter router(RouterRef ref) {
  final AuthNotifier authNotifier = AuthNotifier(ref);

  final GoRouter goRouter = GoRouter(
    refreshListenable: authNotifier,
    redirect: (context, state) async {
      if (authState != UserAuthState.authenticated) {
            return '/${RoutePathConstants.splash}';
        }
        
     return null;
     
    }
    
   ...

 

결론

redirect는 context와 goroute state라는 강력한 변수들을 지원해주기 때문에, 사용자 상태에 따라 다이얼로그를 띄우거나 사용자의 현재 url에 따른 세부화된 로직을 구현할 수 있다는 것이 매우 중요한 것 같다. 사용법을 꼭 숙지하고 있자.