[go_router] Add GoRouterState parameters to GoRouterData and rename replace methods (#2848)
* :sparkles: Add redirectWithState method to GoRouteData
* :white_check_mark: Update the tests
* :arrow_up: Increase version number
* :pencil2: Better changelog
* :boom: Remove xxxWithState and adds a the context and the state as a parameter to all GoRouteData callbacks
* :memo: Update the change logs and version number
* :boom: Rename replace into pushReplacement
* :memo: Add pushReplacementNamed into change log
* :memo: Add migration guide's link to the read me
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index b11aeb4..075e950 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -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.
diff --git a/packages/go_router/README.md b/packages/go_router/README.md
index b0cd9ab..daed219 100644
--- a/packages/go_router/README.md
+++ b/packages/go_router/README.md
@@ -37,6 +37,7 @@
- [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)
diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart
index 82a6e6d..b34aac0 100644
--- a/packages/go_router/lib/src/delegate.dart
+++ b/packages/go_router/lib/src/delegate.dart
@@ -145,7 +145,7 @@
///
/// 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.
}
diff --git a/packages/go_router/lib/src/misc/extensions.dart b/packages/go_router/lib/src/misc/extensions.dart
index 65e45cb..7030ad3 100644
--- a/packages/go_router/lib/src/misc/extensions.dart
+++ b/packages/go_router/lib/src/misc/extensions.dart
@@ -67,8 +67,8 @@
/// 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 @@
/// 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,
diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart
index ba862d0..efa9e85 100644
--- a/packages/go_router/lib/src/route_data.dart
+++ b/packages/go_router/lib/src/route_data.dart
@@ -14,7 +14,7 @@
/// 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 @@
/// 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 @@
}
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,
diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart
index c3fb0a8..73a86c6 100644
--- a/packages/go_router/lib/src/router.dart
+++ b/packages/go_router/lib/src/router.dart
@@ -240,7 +240,7 @@
/// 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 @@
_routerDelegate.navigatorKey.currentContext!,
)
.then<void>((RouteMatchList matchList) {
- routerDelegate.replace(matchList);
+ routerDelegate.pushReplacement(matchList);
});
}
@@ -260,13 +260,13 @@
/// 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,
);
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index af92f1c..edcfd0a 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -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
diff --git a/packages/go_router/test/delegate_test.dart b/packages/go_router/test/delegate_test.dart
index 7df8504..62f4b69 100644
--- a/packages/go_router/test/delegate_test.dart
+++ b/packages/go_router/test/delegate_test.dart
@@ -106,7 +106,7 @@
);
});
- 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 @@
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 @@
const Key('/a-p1'),
);
- goRouter.replace('/a');
+ goRouter.pushReplacement('/a');
await tester.pumpAndSettle();
expect(goRouter.routerDelegate.matches.matches.length, 2);
@@ -181,7 +181,7 @@
);
});
- group('replaceNamed', () {
+ group('pushReplacementNamed', () {
testWidgets(
'It should replace the last match with the given one',
(WidgetTester tester) async {
@@ -210,7 +210,7 @@
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,
diff --git a/packages/go_router/test/route_data_test.dart b/packages/go_router/test/route_data_test.dart
index 4ae12f6..6c8a49a 100644
--- a/packages/go_router/test/route_data_test.dart
+++ b/packages/go_router/test/route_data_test.dart
@@ -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 @@
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 @@
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 @@
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 @@
));
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 @@
));
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 @@
));
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);
},
);
}