Riverpod_Navigator는 상태 관리를 위한 Riverpod과 Navigator 2.0의 선언적 접근 방식을 사용하여 네비게이션을 간소화하는 가벼운 Flutter 패키지입니다. 반응형 라우트 처리를 통해 깔끔하고 확장 가능한 라우팅을 가능하게 하며, 상태 기반으로 앱 내 탐색 흐름을 쉽게 관리할 수 있습니다. 이 패키지는 Riverpod과 원활하게 통합되어 애플리케이션 상태의 변화에 따라 라우트가 동적으로 반응할 수 있도록 합니다. 현대적인 Flutter 앱을 위해 설계되었으며, 라우팅 로직과 UI 컴포넌트 간의 관심사 분리를 통해 유지보수성과 테스트 가능성을 높입니다.
사용 사례
Flutter 앱에서의 선언형 탐색
상태 인식 라우트 전환
공급자 값에 기반한 반응형 라우팅
중첩 라우트를 포함한 복잡한 탐색 흐름
격리된 상태에서 탐색 로직 테스트
주요 기능
상태 관리용 Riverpod과의 통합
Navigator 2.0의 선언적 라우팅 지원
상태에 기반한 동적 경로 업데이트
라우팅 로직의 명확한 분리
경로 정의 및 탐색을 위한 간단한 API
적합한 대상
상태 관리에 Riverpod을 사용하는 개발자
반응형 탐색이 필요한 앱
확장 가능한 라우팅 아키텍처를 목표로 하는 프로젝트
테스트 가능하고 유지보수 가능한 코드에 집중하는 팀
복잡한 탐색을 갖춘 현대적인 Flutter 애플리케이션
고려 사항
Riverpod 및 Navigator 2.0에 익숙해야 합니다
간단한 앱에 복잡성을 추가할 수 있습니다
제한된 플랫폼 지원 (특정 플랫폼이 나열되지 않음)
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
Riverpod navigation
If you are interested in the motivation why the package was created and a detailed description of what problems it solves, read this MEDIUM article:
Simple Flutter navigation with Riverpod.
Simple but powerful Flutter navigation with riverpod and Navigator 2.0 that solves the following:
Strictly typed navigation:
you can use navigate([HomeSegment(),BookSegment(id: 2)]); instead of navigate('home/book;id:2'); in your code
asynchronous navigation ...
... is the case when changing the navigation state requires asynchronous actions (such as loading or saving data from the Internet)
multiple providers ...
... is the case when the navigation state depends on multiple riverpod providers
easier coding:
the navigation problem is reduced to manipulating the class collection
better separation of concerns: UI x Model (thanks to riverpod :+1:):
navigation logic can be developed and tested without typing a single flutter widget
nested navigation
just use the nested riverpod ProviderScope() and Flutter Router widget
Take a look at the following terms related to URL path home/book;id=2
string-path: e.g. home/book;id=2
string-segment: the string-path consists of two slash-delimited string-segments (home and book;id=2)
typed-segment describes coresponding string-segments (HomeSegment() for 'home' and BookSegment(id:2) for 'book;id=2') typed-segment is class TypedSegment {}'s descendant.
Flutter Navigator 2.0 navigation-stack is uniquely determined by the TypedPath (where each TypedPath's TypedSegment instance corresponds to a screen and page instance): pages = [MaterialPage (child: HomeScreen(HomeSegment())), MaterialPage (child: BookScreen(BookSegment(id:2)))]
encode and decncode helps to convert typed-segment to string-segment and back.
Step2 - configure AppNavigator...
... by extending the RNavigator class.
classAppNavigatorextendsRNavigator{
AppNavigator(Ref ref)
: super(
ref,
[
/// 'home' and 'book' strings are used in web URL, e.g. 'home/book;id=2'/// decode is used to decode URL to HomeSegment/BookSegment/// HomeScreen/BookScreen.new are screen builders for a given segmentRRoute<HomeSegment>(
'home',
HomeSegment.decode,
HomeScreen.new,
),
RRoute<BookSegment>(
'book',
BookSegment.decode,
BookScreen.new,
),
],
);
}
Step3 - use the AppNavigator in MaterialApp.router
If you are familiar with the Flutter Navigator 2.0 and the riverpod, the following code is clear:
The link Go to book: [3, 13, 103] in the running example would not make much sense in the real Books application.
But it shows the navigation to the four-screen navigation stack:
Flutter Navigator 2.0 and its MaterialApp.router constructor requires a URL parser (RouteInformationParser).
We use URL syntax, see section 3.3. of RFC 3986, note
*For example, one URI producer might use a segment such as "name;v=1.1"..."
Each TypedSegment must be converted to string-segment and back.
The format of string-segment is
<unique TypedSegment id>[;<property name>=<property value>]*, e.g. book;id=3.
encode/decode example:
Instead of directly converting to/from the string, we convert to/from typedef UrlPars = Map<String,String>
So far, we support the following types of TypedSegment property: int, double, bool, String, int?, double?, bool?, String?.
Every aspect of URL conversion can be customized, e.g.
support another property type (as a DateTime, providing getDateTime, getDateTimeNull and setDateTime in your own UrlPars's extension)
See extension UrlParsEx on UrlPars in
path_parser.dart.
rewrite the entire IPathParser and use a completely different URL syntax. Then use your parser in AppNavigator:
It is good practice to place the code for all events (specific to navigation) in AppNavigator.
These can then be used not only for writing screen widgets, but also for testing.
classAppNavigatorextendsRNavigator{
......
/// navigate to next bookFuturetoNextBook() => replaceLast<BookSegment>((last) => BookSegment(id: last.id + 1));
/// navigate to homeFuturetoHome() => navigate([HomeSegment()]);
}
As you can see, changing the Input state starts the async calculation.
The result of the calculations is Output state which can have app-specific Side effects.
Navigator 2.0 RouterDelegate is then synchronized with navigationStackProvider
Roadmap
I prepared this package for my new project. Its further development depends on whether the community will use it.
proofreading because my English is not good. Community help is warmly welcomed.