mirror of
https://github.com/flutter/packages.git
synced 2025-06-30 14:47:22 +08:00
[go_router] Add GoRouterState parameters to GoRouterData and rename replace methods (#2848)
* ✨ Add redirectWithState method to GoRouteData * ✅ Update the tests * ⬆️ Increase version number * ✏️ Better changelog * 💥 Remove xxxWithState and adds a the context and the state as a parameter to all GoRouteData callbacks * 📝 Update the change logs and version number * 💥 Rename replace into pushReplacement * 📝 Add pushReplacementNamed into change log * 📝 Add migration guide's link to the read me
This commit is contained in:
@ -1,3 +1,13 @@
|
||||
## 6.0.0
|
||||
|
||||
- **BREAKING CHANGE**
|
||||
- `GoRouteData`'s `redirect` now takes 2 parameters `BuildContext context, GoRouterState state`.
|
||||
- `GoRouteData`'s `build` now takes 2 parameters `BuildContext context, GoRouterState state`.
|
||||
- `GoRouteData`'s `buildPageWithState` has been removed and replaced by `buildPage` with now takes 2 parameters `BuildContext context, GoRouterState state`.
|
||||
- `replace` from `GoRouter`, `GoRouterDelegate` and `GoRouterHelper` has been renamed into `pushReplacement`.
|
||||
- `replaceNamed` from `GoRouter`, `GoRouterDelegate` and `GoRouterHelper` has been renamed into `pushReplacementNamed`.
|
||||
- [go_router v6 migration guide](https://flutter.dev/go/go-router-v6-breaking-changes)
|
||||
|
||||
## 5.2.4
|
||||
|
||||
- Fixes crashes when using async redirect.
|
||||
|
@ -37,6 +37,7 @@ See the API documentation for details on the following topics:
|
||||
- [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
|
||||
|
||||
## Migration guides
|
||||
- [Migrating to 6.0.0](https://flutter.dev/go/go-router-v6-breaking-changes)
|
||||
- [Migrating to 5.1.2](https://flutter.dev/go/go-router-v5-1-2-breaking-changes)
|
||||
- [Migrating to 5.0](https://flutter.dev/go/go-router-v5-breaking-changes)
|
||||
- [Migrating to 4.0](https://flutter.dev/go/go-router-v4-breaking-changes)
|
||||
|
@ -145,7 +145,7 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
|
||||
///
|
||||
/// See also:
|
||||
/// * [push] which pushes the given location onto the page stack.
|
||||
void replace(RouteMatchList matches) {
|
||||
void pushReplacement(RouteMatchList matches) {
|
||||
_matchList.pop();
|
||||
push(matches); // [push] will notify the listeners.
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ extension GoRouterHelper on BuildContext {
|
||||
/// See also:
|
||||
/// * [go] which navigates to the location.
|
||||
/// * [push] which pushes the location onto the page stack.
|
||||
void replace(String location, {Object? extra}) =>
|
||||
GoRouter.of(this).replace(location, extra: extra);
|
||||
void pushReplacement(String location, {Object? extra}) =>
|
||||
GoRouter.of(this).pushReplacement(location, extra: extra);
|
||||
|
||||
/// Replaces the top-most page of the page stack with the named route w/
|
||||
/// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid':
|
||||
@ -77,13 +77,13 @@ extension GoRouterHelper on BuildContext {
|
||||
/// See also:
|
||||
/// * [goNamed] which navigates a named route.
|
||||
/// * [pushNamed] which pushes a named route onto the page stack.
|
||||
void replaceNamed(
|
||||
void pushReplacementNamed(
|
||||
String name, {
|
||||
Map<String, String> params = const <String, String>{},
|
||||
Map<String, dynamic> queryParams = const <String, dynamic>{},
|
||||
Object? extra,
|
||||
}) =>
|
||||
GoRouter.of(this).replaceNamed(
|
||||
GoRouter.of(this).pushReplacementNamed(
|
||||
name,
|
||||
params: params,
|
||||
queryParams: queryParams,
|
||||
|
@ -14,7 +14,7 @@ import 'state.dart';
|
||||
/// Baseclass for supporting
|
||||
/// [Type-safe routing](https://pub.dev/documentation/go_router/latest/topics/Type-safe%20routes-topic.html).
|
||||
///
|
||||
/// Subclasses must override one of [build], [buildPageWithState], or
|
||||
/// Subclasses must override one of [build], [buildPage], or
|
||||
/// [redirect].
|
||||
/// {@category Type-safe routes}
|
||||
abstract class GoRouteData {
|
||||
@ -25,53 +25,36 @@ abstract class GoRouteData {
|
||||
|
||||
/// Creates the [Widget] for `this` route.
|
||||
///
|
||||
/// Subclasses must override one of [build], [buildPageWithState], or
|
||||
/// Subclasses must override one of [build], [buildPage], or
|
||||
/// [redirect].
|
||||
///
|
||||
/// Corresponds to [GoRoute.builder].
|
||||
Widget build(BuildContext context) => throw UnimplementedError(
|
||||
'One of `build` or `buildPageWithState` must be implemented.',
|
||||
Widget build(BuildContext context, GoRouterState state) =>
|
||||
throw UnimplementedError(
|
||||
'One of `build` or `buildPage` must be implemented.',
|
||||
);
|
||||
|
||||
/// A page builder for this route.
|
||||
///
|
||||
/// Subclasses can override this function to provide a custom [Page].
|
||||
///
|
||||
/// Subclasses must override one of [build], [buildPageWithState] or
|
||||
/// Subclasses must override one of [build], [buildPage] or
|
||||
/// [redirect].
|
||||
///
|
||||
/// Corresponds to [GoRoute.pageBuilder].
|
||||
///
|
||||
/// By default, returns a [Page] instance that is ignored, causing a default
|
||||
/// [Page] implementation to be used with the results of [build].
|
||||
@Deprecated(
|
||||
'This method has been deprecated in favor of buildPageWithState. '
|
||||
'This feature was deprecated after v4.3.0.',
|
||||
)
|
||||
Page<void> buildPage(BuildContext context) => const NoOpPage();
|
||||
|
||||
/// A page builder for this route with [GoRouterState].
|
||||
///
|
||||
/// Subclasses can override this function to provide a custom [Page].
|
||||
///
|
||||
/// Subclasses must override one of [build], [buildPageWithState] or
|
||||
/// [redirect].
|
||||
///
|
||||
/// Corresponds to [GoRoute.pageBuilder].
|
||||
///
|
||||
/// By default, returns a [Page] instance that is ignored, causing a default
|
||||
/// [Page] implementation to be used with the results of [build].
|
||||
Page<void> buildPageWithState(BuildContext context, GoRouterState state) =>
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
buildPage(context);
|
||||
Page<void> buildPage(BuildContext context, GoRouterState state) =>
|
||||
const NoOpPage();
|
||||
|
||||
/// An optional redirect function for this route.
|
||||
///
|
||||
/// Subclasses must override one of [build], [buildPageWithState], or
|
||||
/// Subclasses must override one of [build], [buildPage], or
|
||||
/// [redirect].
|
||||
///
|
||||
/// Corresponds to [GoRoute.redirect].
|
||||
FutureOr<String?> redirect() => null;
|
||||
FutureOr<String?> redirect(BuildContext context, GoRouterState state) => null;
|
||||
|
||||
/// A helper function used by generated code.
|
||||
///
|
||||
@ -106,13 +89,13 @@ abstract class GoRouteData {
|
||||
}
|
||||
|
||||
Widget builder(BuildContext context, GoRouterState state) =>
|
||||
factoryImpl(state).build(context);
|
||||
factoryImpl(state).build(context, state);
|
||||
|
||||
Page<void> pageBuilder(BuildContext context, GoRouterState state) =>
|
||||
factoryImpl(state).buildPageWithState(context, state);
|
||||
factoryImpl(state).buildPage(context, state);
|
||||
|
||||
FutureOr<String?> redirect(BuildContext context, GoRouterState state) =>
|
||||
factoryImpl(state).redirect();
|
||||
factoryImpl(state).redirect(context, state);
|
||||
|
||||
return GoRoute(
|
||||
path: path,
|
||||
|
@ -240,7 +240,7 @@ class GoRouter extends ChangeNotifier implements RouterConfig<RouteMatchList> {
|
||||
/// See also:
|
||||
/// * [go] which navigates to the location.
|
||||
/// * [push] which pushes the location onto the page stack.
|
||||
void replace(String location, {Object? extra}) {
|
||||
void pushReplacement(String location, {Object? extra}) {
|
||||
routeInformationParser
|
||||
.parseRouteInformationWithDependencies(
|
||||
RouteInformation(location: location, state: extra),
|
||||
@ -249,7 +249,7 @@ class GoRouter extends ChangeNotifier implements RouterConfig<RouteMatchList> {
|
||||
_routerDelegate.navigatorKey.currentContext!,
|
||||
)
|
||||
.then<void>((RouteMatchList matchList) {
|
||||
routerDelegate.replace(matchList);
|
||||
routerDelegate.pushReplacement(matchList);
|
||||
});
|
||||
}
|
||||
|
||||
@ -260,13 +260,13 @@ class GoRouter extends ChangeNotifier implements RouterConfig<RouteMatchList> {
|
||||
/// See also:
|
||||
/// * [goNamed] which navigates a named route.
|
||||
/// * [pushNamed] which pushes a named route onto the page stack.
|
||||
void replaceNamed(
|
||||
void pushReplacementNamed(
|
||||
String name, {
|
||||
Map<String, String> params = const <String, String>{},
|
||||
Map<String, dynamic> queryParams = const <String, dynamic>{},
|
||||
Object? extra,
|
||||
}) {
|
||||
replace(
|
||||
pushReplacement(
|
||||
namedLocation(name, params: params, queryParams: queryParams),
|
||||
extra: extra,
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
name: go_router
|
||||
description: A declarative router for Flutter based on Navigation 2 supporting
|
||||
deep linking, data-driven routes and more
|
||||
version: 5.2.4
|
||||
version: 6.0.0
|
||||
repository: https://github.com/flutter/packages/tree/main/packages/go_router
|
||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
|
||||
|
||||
|
@ -106,7 +106,7 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
group('replace', () {
|
||||
group('pushReplacement', () {
|
||||
testWidgets('It should replace the last match with the given one',
|
||||
(WidgetTester tester) async {
|
||||
final GoRouter goRouter = GoRouter(
|
||||
@ -128,7 +128,7 @@ void main() {
|
||||
goRouter.routerDelegate.addListener(expectAsync0(() {}));
|
||||
final RouteMatch first = goRouter.routerDelegate.matches.matches.first;
|
||||
final RouteMatch last = goRouter.routerDelegate.matches.last;
|
||||
goRouter.replace('/page-1');
|
||||
goRouter.pushReplacement('/page-1');
|
||||
expect(goRouter.routerDelegate.matches.matches.length, 2);
|
||||
expect(
|
||||
goRouter.routerDelegate.matches.matches.first,
|
||||
@ -169,7 +169,7 @@ void main() {
|
||||
const Key('/a-p1'),
|
||||
);
|
||||
|
||||
goRouter.replace('/a');
|
||||
goRouter.pushReplacement('/a');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(goRouter.routerDelegate.matches.matches.length, 2);
|
||||
@ -181,7 +181,7 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
group('replaceNamed', () {
|
||||
group('pushReplacementNamed', () {
|
||||
testWidgets(
|
||||
'It should replace the last match with the given one',
|
||||
(WidgetTester tester) async {
|
||||
@ -210,7 +210,7 @@ void main() {
|
||||
goRouter.routerDelegate.addListener(expectAsync0(() {}));
|
||||
final RouteMatch first = goRouter.routerDelegate.matches.matches.first;
|
||||
final RouteMatch last = goRouter.routerDelegate.matches.last;
|
||||
goRouter.replaceNamed('page1');
|
||||
goRouter.pushReplacementNamed('page1');
|
||||
expect(goRouter.routerDelegate.matches.matches.length, 2);
|
||||
expect(
|
||||
goRouter.routerDelegate.matches.matches.first,
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@ -9,7 +11,8 @@ import 'package:go_router/go_router.dart';
|
||||
class _GoRouteDataBuild extends GoRouteData {
|
||||
const _GoRouteDataBuild();
|
||||
@override
|
||||
Widget build(BuildContext context) => const SizedBox(key: Key('build'));
|
||||
Widget build(BuildContext context, GoRouterState state) =>
|
||||
const SizedBox(key: Key('build'));
|
||||
}
|
||||
|
||||
final GoRoute _goRouteDataBuild = GoRouteData.$route(
|
||||
@ -20,7 +23,8 @@ final GoRoute _goRouteDataBuild = GoRouteData.$route(
|
||||
class _GoRouteDataBuildPage extends GoRouteData {
|
||||
const _GoRouteDataBuildPage();
|
||||
@override
|
||||
Page<void> buildPage(BuildContext context) => const MaterialPage<void>(
|
||||
Page<void> buildPage(BuildContext context, GoRouterState state) =>
|
||||
const MaterialPage<void>(
|
||||
child: SizedBox(key: Key('buildPage')),
|
||||
);
|
||||
}
|
||||
@ -30,24 +34,22 @@ final GoRoute _goRouteDataBuildPage = GoRouteData.$route(
|
||||
factory: (GoRouterState state) => const _GoRouteDataBuildPage(),
|
||||
);
|
||||
|
||||
class _GoRouteDataBuildPageWithState extends GoRouteData {
|
||||
const _GoRouteDataBuildPageWithState();
|
||||
class _GoRouteDataRedirectPage extends GoRouteData {
|
||||
const _GoRouteDataRedirectPage();
|
||||
@override
|
||||
Page<void> buildPageWithState(BuildContext context, GoRouterState state) =>
|
||||
const MaterialPage<void>(
|
||||
child: SizedBox(key: Key('buildPageWithState')),
|
||||
);
|
||||
FutureOr<String> redirect(BuildContext context, GoRouterState state) =>
|
||||
'/build-page';
|
||||
}
|
||||
|
||||
final GoRoute _goRouteDataBuildPageWithState = GoRouteData.$route(
|
||||
path: '/build-page-with-state',
|
||||
factory: (GoRouterState state) => const _GoRouteDataBuildPageWithState(),
|
||||
final GoRoute _goRouteDataRedirect = GoRouteData.$route(
|
||||
path: '/redirect',
|
||||
factory: (GoRouterState state) => const _GoRouteDataRedirectPage(),
|
||||
);
|
||||
|
||||
final List<GoRoute> _routes = <GoRoute>[
|
||||
_goRouteDataBuild,
|
||||
_goRouteDataBuildPage,
|
||||
_goRouteDataBuildPageWithState,
|
||||
_goRouteDataRedirect,
|
||||
];
|
||||
|
||||
void main() {
|
||||
@ -65,7 +67,6 @@ void main() {
|
||||
));
|
||||
expect(find.byKey(const Key('build')), findsOneWidget);
|
||||
expect(find.byKey(const Key('buildPage')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPageWithState')), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
@ -83,12 +84,11 @@ void main() {
|
||||
));
|
||||
expect(find.byKey(const Key('build')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPage')), findsOneWidget);
|
||||
expect(find.byKey(const Key('buildPageWithState')), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'It should build the page from the overridden buildPageWithState method',
|
||||
'It should build the page from the overridden buildPage method',
|
||||
(WidgetTester tester) async {
|
||||
final GoRouter goRouter = GoRouter(
|
||||
initialLocation: '/build-page-with-state',
|
||||
@ -101,7 +101,39 @@ void main() {
|
||||
));
|
||||
expect(find.byKey(const Key('build')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPage')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPageWithState')), findsOneWidget);
|
||||
},
|
||||
);
|
||||
testWidgets(
|
||||
'It should redirect using the overridden redirect method',
|
||||
(WidgetTester tester) async {
|
||||
final GoRouter goRouter = GoRouter(
|
||||
initialLocation: '/redirect',
|
||||
routes: _routes,
|
||||
);
|
||||
await tester.pumpWidget(MaterialApp.router(
|
||||
routeInformationProvider: goRouter.routeInformationProvider,
|
||||
routeInformationParser: goRouter.routeInformationParser,
|
||||
routerDelegate: goRouter.routerDelegate,
|
||||
));
|
||||
expect(find.byKey(const Key('build')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPage')), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'It should redirect using the overridden redirect method',
|
||||
(WidgetTester tester) async {
|
||||
final GoRouter goRouter = GoRouter(
|
||||
initialLocation: '/redirect-with-state',
|
||||
routes: _routes,
|
||||
);
|
||||
await tester.pumpWidget(MaterialApp.router(
|
||||
routeInformationProvider: goRouter.routeInformationProvider,
|
||||
routeInformationParser: goRouter.routeInformationParser,
|
||||
routerDelegate: goRouter.routerDelegate,
|
||||
));
|
||||
expect(find.byKey(const Key('build')), findsNothing);
|
||||
expect(find.byKey(const Key('buildPage')), findsNothing);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user