나중에 참고하면 좋은 사이트
https://www.kodeco.com/flutter/paths/flutter-fundamentals
GoRouter
class MyRouter {
// 로그인 상태
final LoginState loginState;
MyRouter(this.loginState);
// 기본 Router()
late final router = GoRouter(
// 각페이지의 루트 포함
routes: [],
// loginState 상태를 지켜본다.
refreshListenable: loginState,
// 개발시 디버그하기, 앱출시에는 false 로 변경해야한다.
debugLogDiagnostics: true,
);
}
late final router = GoRouter(
// 길 들
routes: [
// 길 등록
GoRoute(
// 길
path: '/login',
// 길 이름 (겹치면 안된다.)
name: loginRouteName,
// 도착치
builder: (context, state) {
return const Login();
},
),
// 길 등록,
// 길 등록,
],
refreshListenable: loginState,
debugLogDiagnostics: true,
);
late final router = GoRouter(
errorBuilder: (context, state) {
// 에러 페이지출력
return ErrorPage(error: state.error)
}
errorPageBuilder: (context, state) {
return MaterialPage<void>(child: ErrorPage());
}
...
);
결과적으로 같다.
기본적인 트랜지션을 사용할때는 errorBuilder 사용
커스텀 트랜지션은 errorPageBuilder 사용한다.
errorPagebuilder 같은 경우는 MaterialPage처럼컨트롤 가능해진다.
context.go('/login');
context.goNamed(routeName);
context.pushNamed(routeName);
go 는 라우트 스택에 안쌓인다.
push 는 라우트 스택에 쌓인다. 그래서 뒤로가기 버튼 생김
어떤 경로로 다시 보내버리겠다. 라는 의미이다.
refreshListenable: loginState
loginState 의 상태가 변경되어 리프래쉬 되는 것을 읽겠다.
GoRouter(
...
routes: [라우트들],
redirect: (context, state) {
// 현재 우리가 보고있는 페이지 확인
// 현재 로그인 상태 어떤지 확인
final loggedIn = loginState.loggedIn;
// state.subloc : 현재 위치해 있는 쿼리파라미터를 리턴한다.
final inAuthPages = state.subloc.contains(loginRouteName) ||
state.subloc.contains(createAccountRouteName);
// inAuth && true => go to home
if(inAuthPages && loggedIn) return '/';
// noInAuth && false => go to loginPage
if(!inAuthPages && !loggedIn) return '/login';
},
// loginState 상태를 지켜본다.
refreshListenable: loginState,
)
HomeScreen() 에는 tab 을 받아서 바텀시트를 변경하는데, 하드코딩으로 하지말고, state의 파람을 매개변수를 받아 전달하면 동적으로 잘 전달된다.
GoRoute(
path: '/',
name: rootRouteName,
builder: (context, state) {
return HomeScreen(tab: 'shopping');
},
),
경로의 매개변수 받기!
GoRoute(
path: '/:tab',
name: rootRouteName,
builder: (context, state) {
final tab = state.params['tab'];
// 빈값을
return HomeScreen(tab: tab ?? '');
},
),
기존 경로에 서브 경로를 넣어줄 수있다.
GoRoute(
path: '/:tab',
name: rootRouteName,
builder: (context, state) {
final tab = state.params['tab'];
return HomeScreen(tab: tab ?? '');
},
routes: [
GoRoute(
name: profilePersonalRouteName,
path: 'personal',
builder: (context, state) {
return const PersonalInfo();
},
),
]),
/:tab/profile-personal
/profile/profile-personal
onTap: () {
// TODO: Add Personal Page Route
context.pushNamed(
profilePersonalRouteName,
// /:tab 을 넣어줘야 에러가 안난다.
params: {'tab': 'profile'},
);
},
debugLogDiagnostics: true, 했을시 나오는 bash
[GoRouter] Full paths for routes:
=> /login
=> /create-account
=> /:tab
=> /:tab/personal
known full paths for route names:
login => /login
create-account => /create-account
root => /:tab
profile-personal => /:tab/personal
[GoRouter] setting initial location /login
[GoRouter] redirecting to RouteMatchList(/:tab)
[GoRouter] Using MaterialApp configuration
바텀 모델을 클릭해도 위의 경로가 바뀌지 않는다.
크롬으로 확인해보자!
바텀 시트 코드 변경
onTap: (index) {
switch (index) {
case 0:
context.go('/shop');
break;
case 1:
context.go('/cart');
break;
case 2:
context.go('/profile');
break;
}
GoRoute(
name: shopDetailsRouteName,
path: 'details/:item',
builder: (context, state) {
return Details(description: state.params['item']!);
},
),
onTap: () {
final value = items[index];
context.goNamed(
shopDetailsRouteName,
params: {'tab': 'shop', 'item': value},
);
결과
이런식으로 profile 의 서브 경로도 연결해주자!
context.pushNamed(
profilePersonalRouteName,
params: {'tab': 'profile'},
);
ListTile(
title: Text(
'log out',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
logOut(context);
},
),
// 로그아웃 함수
void logOut(BuildContext context) {
Provider.of<LoginState>(context, listen: false).loggedIn = false;
}
그리고 goRouter 등록할때, redirect를 하기
redirect: (context, state) {
// 현재 우리가 보고있는 페이지 확인
// 현재 로그인 상태 어떤지 확인
final loggedIn = loginState.loggedIn;
// state.subloc : 현재 위치해 있는 쿼리파라미터를 리턴한다.
final inAuthPages = state.subloc.contains(loginRouteName) ||
state.subloc.contains(createAccountRouteName);
// inAuth && true => go to home
if (inAuthPages && loggedIn) return '/shop';
// noInAuth && false => go to loginPage
if (!inAuthPages && !loggedIn) return '/login';
},
전달 하는 곳
context.goNamed(
shopDetailsRouteName,
params: {'tab': 'shop', 'item': value},
// 어떤 Object? 든 보낼수 있다.
extra: 'TestText - $value'
);
전달 받는 라우터 설정
GoRoute(
name: shopDetailsRouteName,
path: 'details/:item',
builder: (context, state) {
return Details(
description: state.params['item']!,
// extra 로 던져주기
extra: state.extra,
);
},
),
전달 받는 곳
class Details extends StatelessWidget {
final Object? extra;
Details({..., this.extra});
return(
...
// String 인거는 이미 아니깐, 캐스팅해준다.
Text('extra- ${extra as String}'),
)
정리가 참 잘되어있네요 감사합니다!!