[go_router] Fixes the GoRouter.goBranch so that it doesn't reset extr… (#4723)
â¦a to null if extra is not serializable.
This was a mistake I made when I refactor the code, the goBranch uses GoRouter.restore which will go through unnecessary serialize/deserialize. Fixing this will unfortunately introduce a breaking change, though I don't think a lot of people will be impacted by this.
I will write a migration guide soon
fixes https://github.com/flutter/flutter/issues/129347
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index d8ce441..a52afff 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 11.0.0
+
+- Fixes the GoRouter.goBranch so that it doesn't reset extra to null if extra is not serializable.
+- **BREAKING CHANGE**:
+ - Updates the function signature of `GoRouteInformationProvider.restore`.
+ - Adds `NavigationType.restore` to `NavigationType` enum.
+
## 10.2.0
- Adds `onExit` to GoRoute.
diff --git a/packages/go_router/README.md b/packages/go_router/README.md
index 0a72dd1..f2cd542 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 11.0.0](https://flutter.dev/go/go-router-v11-breaking-changes).
- [Migrating to 10.0.0](https://flutter.dev/go/go-router-v10-breaking-changes).
- [Migrating to 9.0.0](https://flutter.dev/go/go-router-v9-breaking-changes).
- [Migrating to 8.0.0](https://flutter.dev/go/go-router-v8-breaking-changes).
diff --git a/packages/go_router/lib/src/information_provider.dart b/packages/go_router/lib/src/information_provider.dart
index 31a9e69..9346c2a 100644
--- a/packages/go_router/lib/src/information_provider.dart
+++ b/packages/go_router/lib/src/information_provider.dart
@@ -33,6 +33,10 @@
/// Replace the entire [RouteMatchList] with the new location.
go,
+
+ /// Restore the current match list with
+ /// [RouteInformationState.baseRouteMatchList].
+ restore,
}
/// The data class to be stored in [RouteInformation.state] to be used by
@@ -48,8 +52,9 @@
this.completer,
this.baseRouteMatchList,
required this.type,
- }) : assert((type != NavigatingType.go) ==
- (completer != null && baseRouteMatchList != null));
+ }) : assert((type == NavigatingType.go || type == NavigatingType.restore) ==
+ (completer == null)),
+ assert((type != NavigatingType.go) == (baseRouteMatchList != null));
/// The extra object used when navigating with [GoRouter].
final Object? extra;
@@ -57,7 +62,8 @@
/// The completer that needs to be completed when the newly added route is
/// popped off the screen.
///
- /// This is only null if [type] is [NavigatingType.go].
+ /// This is only null if [type] is [NavigatingType.go] or
+ /// [NavigatingType.restore].
final Completer<T?>? completer;
/// The base route match list to push on top to.
@@ -177,11 +183,15 @@
);
}
- /// Restores the current route matches with the `encodedMatchList`.
- void restore(String location, {required Object encodedMatchList}) {
+ /// Restores the current route matches with the `matchList`.
+ void restore(String location, {required RouteMatchList matchList}) {
_setValue(
- location,
- encodedMatchList,
+ matchList.uri.toString(),
+ RouteInformationState<void>(
+ extra: matchList.extra,
+ baseRouteMatchList: matchList,
+ type: NavigatingType.restore,
+ ),
);
}
diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart
index cc5ca70..41f6ef8 100644
--- a/packages/go_router/lib/src/parser.dart
+++ b/packages/go_router/lib/src/parser.dart
@@ -193,6 +193,11 @@
);
case NavigatingType.go:
return newMatchList;
+ case NavigatingType.restore:
+ // Still need to consider redirection.
+ return baseRouteMatchList!.uri.toString() == newMatchList.uri.toString()
+ ? baseRouteMatchList
+ : newMatchList;
}
}
diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart
index a5671e2..e37151d 100644
--- a/packages/go_router/lib/src/router.dart
+++ b/packages/go_router/lib/src/router.dart
@@ -327,7 +327,7 @@
log.info('restoring ${matchList.uri}');
routeInformationProvider.restore(
matchList.uri.toString(),
- encodedMatchList: RouteMatchListCodec(configuration).encode(matchList),
+ matchList: matchList,
);
}
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 128569f..4e3ba3d 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: 10.2.0
+version: 11.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/go_router_test.dart b/packages/go_router/test/go_router_test.dart
index 2d67029..107e828 100644
--- a/packages/go_router/test/go_router_test.dart
+++ b/packages/go_router/test/go_router_test.dart
@@ -2843,6 +2843,52 @@
expect(matches.pathParameters['pid'], pid);
});
+ testWidgets('StatefulShellRoute preserve extra when switching branch',
+ (WidgetTester tester) async {
+ StatefulNavigationShell? routeState;
+ Object? latestExtra;
+ final List<RouteBase> routes = <RouteBase>[
+ StatefulShellRoute.indexedStack(
+ builder: (BuildContext context, GoRouterState state,
+ StatefulNavigationShell navigationShell) {
+ routeState = navigationShell;
+ return navigationShell;
+ },
+ branches: <StatefulShellBranch>[
+ StatefulShellBranch(
+ routes: <RouteBase>[
+ GoRoute(
+ path: '/a',
+ builder: (BuildContext context, GoRouterState state) =>
+ const Text('Screen A'),
+ ),
+ ],
+ ),
+ StatefulShellBranch(
+ routes: <RouteBase>[
+ GoRoute(
+ path: '/b',
+ builder: (BuildContext context, GoRouterState state) {
+ latestExtra = state.extra;
+ return const DummyScreen();
+ }),
+ ],
+ ),
+ ],
+ ),
+ ];
+ final Object expectedExtra = Object();
+
+ await createRouter(routes, tester,
+ initialLocation: '/b', initialExtra: expectedExtra);
+ expect(latestExtra, expectedExtra);
+ routeState!.goBranch(0);
+ await tester.pumpAndSettle();
+ routeState!.goBranch(1);
+ await tester.pumpAndSettle();
+ expect(latestExtra, expectedExtra);
+ });
+
testWidgets('goNames should allow dynamics values for queryParams',
(WidgetTester tester) async {
const Map<String, dynamic> queryParametersAll = <String, List<dynamic>>{