[go_router] Replaces uri related properties in GoRouterState (#4392)

Replaces uri related field in GoRouterState, so that we don't need to mimic the API in uri. This also give developer the access to other field like http scheme(once supported) and fragment.
This commit is contained in:
chunhtai
2023-07-21 15:33:59 -07:00
committed by GitHub
parent 43052d9a88
commit 88a48ffb11
17 changed files with 139 additions and 98 deletions

View File

@ -1,3 +1,10 @@
## 10.0.0
- **BREAKING CHANGE**:
- Replaces location, queryParameters, and queryParametersAll in GoRouterState with Uri.
- See [Migrating to 10.0.0](https://flutter.dev/go/go-router-v10-breaking-changes) or
run `dart fix --apply` to fix the breakages.
## 9.1.1
- Fixes a link in error handling documentation.

View File

@ -36,7 +36,8 @@ See the API documentation for details on the following topics:
- [Named routes](https://pub.dev/documentation/go_router/latest/topics/Named%20routes-topic.html)
- [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
## Migration guides
## Migration Guides
- [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).
- [Migrating to 7.0.0](https://flutter.dev/go/go-router-v7-breaking-changes).
@ -53,6 +54,15 @@ See the
[Changelog](https://github.com/flutter/packages/blob/main/packages/go_router/CHANGELOG.md)
for a list of new features and breaking changes.
## Roadmap
See the [GitHub project](https://github.com/orgs/flutter/projects/17/) for a
prioritized list of feature requests and known issues.
## Triage
See the [GitHub issues](https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+label%3Ateam-go_router+)
for all Go Router issues.
The project follows the same priority system as flutter framework.
[P0](https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+label%3Ateam-go_router+label%3AP0+)
[P1](https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+label%3Ateam-go_router+label%3AP1+)
[P2](https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+label%3Ateam-go_router+label%3AP2+)
[P3](https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc+label%3Ateam-go_router+label%3AP3+)
[Package PRs](https://github.com/flutter/packages/pulls?q=is%3Apr+is%3Aopen+label%3A%22p%3A+go_router%22%2C%22p%3A+go_router_builder%22)

View File

@ -17,7 +17,7 @@ void main() => runApp(const MyApp());
/// The route configuration.
final GoRouter _router = GoRouter(
onException: (_, GoRouterState state, GoRouter router) {
router.go('/404', extra: state.location);
router.go('/404', extra: state.uri.toString());
},
routes: <RouteBase>[
GoRoute(

View File

@ -32,7 +32,7 @@ class App extends StatelessWidget {
path: '/page2',
builder: (BuildContext context, GoRouterState state) =>
Page2ScreenWithPush(
int.parse(state.queryParameters['push-count']!),
int.parse(state.uri.queryParameters['push-count']!),
),
),
],

View File

@ -85,7 +85,7 @@ class App extends StatelessWidget {
builder: (BuildContext context, GoRouterState state) {
return FamilyScreen(
fid: state.pathParameters['fid']!,
asc: state.queryParameters['sort'] == 'asc',
asc: state.uri.queryParameters['sort'] == 'asc',
);
}),
],

View File

@ -152,7 +152,7 @@ class ScaffoldWithNavBar extends StatelessWidget {
}
static int _calculateSelectedIndex(BuildContext context) {
final String location = GoRouterState.of(context).location;
final String location = GoRouterState.of(context).uri.toString();
if (location.startsWith('/a')) {
return 0;
}

View File

@ -17,6 +17,42 @@
version: 1
transforms:
- title: "Replaces 'location' in 'GoRouterState' with `uri.toString()`"
date: 2023-07-06
bulkApply: true
element:
# TODO(ahmednfwela): Workaround for https://github.com/dart-lang/sdk/issues/52233
uris: [ 'go_router.dart', 'package:go_router/go_router.dart' ]
field: 'location'
inClass: 'GoRouterState'
changes:
- kind: 'rename'
newName: 'uri.toString()'
- title: "Replaces 'queryParameters' in 'GoRouterState' with `uri.queryParameters`"
date: 2023-07-06
bulkApply: true
element:
# TODO(ahmednfwela): Workaround for https://github.com/dart-lang/sdk/issues/52233
uris: [ 'go_router.dart', 'package:go_router/go_router.dart' ]
field: 'queryParameters'
inClass: 'GoRouterState'
changes:
- kind: 'rename'
newName: 'uri.queryParameters'
- title: "Replaces 'queryParametersAll' in 'GoRouterState' with `uri.queryParametersAll`"
date: 2023-07-06
bulkApply: true
element:
# TODO(ahmednfwela): Workaround for https://github.com/dart-lang/sdk/issues/52233
uris: [ 'go_router.dart', 'package:go_router/go_router.dart' ]
field: 'queryParametersAll'
inClass: 'GoRouterState'
changes:
- kind: 'rename'
newName: 'uri.queryParametersAll'
- title: "Replaces 'params' and 'queryParams' in 'GoRouter.replaceNamed' with `pathParameters` and `queryParameters`"
date: 2023-04-24
bulkApply: true

View File

@ -339,7 +339,7 @@ class RouteBuilder {
}
return GoRouterState(
configuration,
location: effectiveMatchList.uri.toString(),
uri: effectiveMatchList.uri,
matchedLocation: match.matchedLocation,
name: name,
path: path,
@ -347,8 +347,6 @@ class RouteBuilder {
pathParameters:
Map<String, String>.from(effectiveMatchList.pathParameters),
error: effectiveMatchList.error,
queryParameters: effectiveMatchList.uri.queryParameters,
queryParametersAll: effectiveMatchList.uri.queryParametersAll,
extra: effectiveMatchList.extra,
pageKey: match.pageKey,
);
@ -467,7 +465,7 @@ class RouteBuilder {
name: state.name ?? state.path,
arguments: <String, String>{
...state.pathParameters,
...state.queryParameters
...state.uri.queryParameters
},
restorationId: state.pageKey.value,
child: child,
@ -491,18 +489,15 @@ class RouteBuilder {
);
GoRouterState _buildErrorState(RouteMatchList matchList) {
final String location = matchList.uri.toString();
assert(matchList.isError);
return GoRouterState(
configuration,
location: location,
uri: matchList.uri,
matchedLocation: matchList.uri.path,
fullPath: matchList.fullPath,
pathParameters: matchList.pathParameters,
queryParameters: matchList.uri.queryParameters,
queryParametersAll: matchList.uri.queryParametersAll,
error: matchList.error,
pageKey: ValueKey<String>('$location(error)'),
pageKey: ValueKey<String>('${matchList.uri}(error)'),
);
}

View File

@ -202,14 +202,12 @@ class RouteConfiguration {
GoRouterState buildTopLevelGoRouterState(RouteMatchList matchList) {
return GoRouterState(
this,
location: matchList.uri.toString(),
uri: matchList.uri,
// No name available at the top level trim the query params off the
// sub-location to match route.redirect
fullPath: matchList.fullPath,
pathParameters: matchList.pathParameters,
matchedLocation: matchList.uri.path,
queryParameters: matchList.uri.queryParameters,
queryParametersAll: matchList.uri.queryParametersAll,
extra: matchList.extra,
pageKey: const ValueKey<String>('topLevel'),
);
@ -467,15 +465,13 @@ class RouteConfiguration {
context,
GoRouterState(
this,
location: matchList.uri.toString(),
uri: matchList.uri,
matchedLocation: match.matchedLocation,
name: route.name,
path: route.path,
fullPath: matchList.fullPath,
extra: matchList.extra,
pathParameters: matchList.pathParameters,
queryParameters: matchList.uri.queryParameters,
queryParametersAll: matchList.uri.queryParametersAll,
pageKey: match.pageKey,
),
);

View File

@ -16,22 +16,20 @@ class GoRouterState {
/// Default constructor for creating route state during routing.
const GoRouterState(
this._configuration, {
required this.location,
required this.uri,
required this.matchedLocation,
this.name,
this.path,
required this.fullPath,
required this.pathParameters,
required this.queryParameters,
required this.queryParametersAll,
this.extra,
this.error,
required this.pageKey,
});
final RouteConfiguration _configuration;
/// The full location of the route, e.g. /family/f2/person/p1
final String location;
/// The full uri of the route, e.g. /family/f2/person/p1?filter=name#fragment
final Uri uri;
/// The matched location until this point.
///
@ -63,13 +61,6 @@ class GoRouterState {
/// The parameters for this match, e.g. {'fid': 'f2'}
final Map<String, String> pathParameters;
/// The query parameters for the location, e.g. {'from': '/family/f2'}
final Map<String, String> queryParameters;
/// The query parameters for the location,
/// e.g. `{'q1': ['v1'], 'q2': ['v2', 'v3']}`
final Map<String, List<String>> queryParametersAll;
/// An extra object to pass along with the navigation.
final Object? extra;
@ -150,14 +141,12 @@ class GoRouterState {
@override
bool operator ==(Object other) {
return other is GoRouterState &&
other.location == location &&
other.uri == uri &&
other.matchedLocation == matchedLocation &&
other.name == name &&
other.path == path &&
other.fullPath == fullPath &&
other.pathParameters == pathParameters &&
other.queryParameters == queryParameters &&
other.queryParametersAll == queryParametersAll &&
other.extra == extra &&
other.error == error &&
other.pageKey == pageKey;
@ -165,17 +154,16 @@ class GoRouterState {
@override
int get hashCode => Object.hash(
location,
uri,
matchedLocation,
name,
path,
fullPath,
pathParameters,
queryParameters,
queryParametersAll,
extra,
error,
pageKey);
pageKey,
);
}
/// An inherited widget to host a [GoRouterStateRegistry] for the subtree.

View File

@ -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: 9.1.1
version: 10.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

View File

@ -69,7 +69,7 @@ void main() {
Text('redirected ${state.extra}')),
], tester,
onException: (_, GoRouterState state, GoRouter router) =>
router.go('/error', extra: state.location));
router.go('/error', extra: state.uri.toString()));
expect(find.text('redirected /'), findsOneWidget);
router.go('/some-other-location');

View File

@ -17,13 +17,13 @@ void main() {
path: '/',
builder: (BuildContext context, _) {
final GoRouterState state = GoRouterState.of(context);
return Text('/ ${state.queryParameters['p']}');
return Text('/ ${state.uri.queryParameters['p']}');
}),
GoRoute(
path: '/a',
builder: (BuildContext context, _) {
final GoRouterState state = GoRouterState.of(context);
return Text('/a ${state.queryParameters['p']}');
return Text('/a ${state.uri.queryParameters['p']}');
}),
];
final GoRouter router = await createRouter(routes, tester);
@ -42,7 +42,7 @@ void main() {
path: '/',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text('1 ${GoRouterState.of(context).location}');
return Text('1 ${GoRouterState.of(context).uri}');
});
},
routes: <GoRoute>[
@ -50,7 +50,7 @@ void main() {
path: 'a',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text('2 ${GoRouterState.of(context).location}');
return Text('2 ${GoRouterState.of(context).uri}');
});
}),
]),
@ -74,7 +74,7 @@ void main() {
path: '/',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text('1 ${GoRouterState.of(context).location}');
return Text('1 ${GoRouterState.of(context).uri}');
});
},
routes: <GoRoute>[
@ -110,7 +110,7 @@ void main() {
path: '/',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text(GoRouterState.of(context).location);
return Text(GoRouterState.of(context).uri.toString());
});
},
routes: <GoRoute>[
@ -118,7 +118,8 @@ void main() {
path: 'a',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text(key: key, GoRouterState.of(context).location);
return Text(
key: key, GoRouterState.of(context).uri.toString());
});
}),
]),
@ -152,7 +153,7 @@ void main() {
path: '/',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text(GoRouterState.of(context).location);
return Text(GoRouterState.of(context).uri.toString());
});
},
routes: <GoRoute>[
@ -160,7 +161,8 @@ void main() {
path: 'a',
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text(key: key, GoRouterState.of(context).location);
return Text(
key: key, GoRouterState.of(context).uri.toString());
});
}),
]),

View File

@ -474,7 +474,7 @@ void main() {
name: 'home',
path: '/',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/');
expect(state.uri.toString(), '/');
expect(state.matchedLocation, '/');
expect(state.name, 'home');
expect(state.path, '/');
@ -491,7 +491,7 @@ void main() {
name: 'login',
path: 'login',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/login');
expect(state.uri.toString(), '/login');
expect(state.matchedLocation, '/login');
expect(state.name, 'login');
expect(state.path, 'login');
@ -507,7 +507,7 @@ void main() {
path: 'family/:fid',
builder: (BuildContext context, GoRouterState state) {
expect(
state.location,
state.uri.toString(),
anyOf(<String>['/family/f2', '/family/f2/person/p1']),
);
expect(state.matchedLocation, '/family/f2');
@ -524,7 +524,7 @@ void main() {
name: 'person',
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/family/f2/person/p1');
expect(state.uri.toString(), '/family/f2/person/p1');
expect(state.matchedLocation, '/family/f2/person/p1');
expect(state.name, 'person');
expect(state.path, 'person/:pid');
@ -1604,7 +1604,7 @@ void main() {
name: 'page1',
path: '/page1',
builder: (BuildContext c, GoRouterState s) {
expect(s.queryParameters['param1'], param1);
expect(s.uri.queryParameters['param1'], param1);
return const DummyScreen();
},
),
@ -1673,7 +1673,7 @@ void main() {
GoRoute(
path: 'dummy',
// Return same location.
redirect: (_, GoRouterState state) => state.location,
redirect: (_, GoRouterState state) => state.uri.toString(),
builder: (BuildContext context, GoRouterState state) =>
const DummyScreen()),
],
@ -1683,7 +1683,7 @@ void main() {
final GoRouter router = await createRouter(routes, tester,
redirect: (BuildContext context, GoRouterState state) {
// Return same location.
return state.location;
return state.uri.toString();
});
expect(router.routerDelegate.currentConfiguration.uri.toString(), '/');
@ -1950,7 +1950,7 @@ void main() {
tester,
redirect: (BuildContext context, GoRouterState state) =>
state.matchedLocation == '/'
? '/login?from=${state.location}'
? '/login?from=${state.uri}'
: state.matchedLocation == '/login'
? '/'
: null,
@ -2009,13 +2009,13 @@ void main() {
tester,
initialLocation: '/login?from=/',
redirect: (BuildContext context, GoRouterState state) {
expect(Uri.parse(state.location).queryParameters, isNotEmpty);
expect(Uri.parse(state.uri.toString()).queryParameters, isNotEmpty);
expect(Uri.parse(state.matchedLocation).queryParameters, isEmpty);
expect(state.path, isNull);
expect(state.fullPath, '/login');
expect(state.pathParameters.length, 0);
expect(state.queryParameters.length, 1);
expect(state.queryParameters['from'], '/');
expect(state.uri.queryParameters.length, 1);
expect(state.uri.queryParameters['from'], '/');
return null;
},
);
@ -2066,12 +2066,12 @@ void main() {
GoRoute(
path: '/book/:bookId',
redirect: (BuildContext context, GoRouterState state) {
expect(state.location, loc);
expect(state.uri.toString(), loc);
expect(state.matchedLocation, loc);
expect(state.path, '/book/:bookId');
expect(state.fullPath, '/book/:bookId');
expect(state.pathParameters, <String, String>{'bookId': '0'});
expect(state.queryParameters.length, 0);
expect(state.uri.queryParameters.length, 0);
return null;
},
builder: (BuildContext c, GoRouterState s) => const HomeScreen(),
@ -2142,7 +2142,7 @@ void main() {
<GoRoute>[],
tester,
redirect: (BuildContext context, GoRouterState state) =>
'/${state.location}+',
'/${state.uri}+',
errorBuilder: (BuildContext context, GoRouterState state) =>
TestErrorScreen(state.error!),
redirectLimit: 10,
@ -2164,7 +2164,7 @@ void main() {
],
tester,
errorBuilder: (_, GoRouterState state) {
return Text(state.location);
return Text(state.uri.toString());
},
);
@ -2230,7 +2230,7 @@ void main() {
routes,
tester,
redirect: (BuildContext context, GoRouterState state) {
if (state.location == '/login') {
if (state.uri.toString() == '/login') {
isCallTopRedirect = true;
expect(state.extra, isNotNull);
}
@ -2460,7 +2460,7 @@ void main() {
GoRoute(
path: '/family',
builder: (BuildContext context, GoRouterState state) => FamilyScreen(
state.queryParameters['fid']!,
state.uri.queryParameters['fid']!,
),
),
];
@ -2510,7 +2510,7 @@ void main() {
GoRoute(
path: '/page1',
builder: (BuildContext c, GoRouterState s) {
expect(s.queryParameters['param1'], param1);
expect(s.uri.queryParameters['param1'], param1);
return const DummyScreen();
},
),
@ -2561,8 +2561,8 @@ void main() {
builder: (BuildContext context, GoRouterState state) {
log.info('id= ${state.pathParameters['id']}');
expect(state.pathParameters.length, 0);
expect(state.queryParameters.length, 1);
expect(state.queryParameters['id'], anyOf('0', '1'));
expect(state.uri.queryParameters.length, 1);
expect(state.uri.queryParameters['id'], anyOf('0', '1'));
return const HomeScreen();
},
),
@ -2583,7 +2583,7 @@ void main() {
path: '/:id',
builder: (BuildContext context, GoRouterState state) {
expect(state.pathParameters, <String, String>{'id': '0'});
expect(state.queryParameters, <String, String>{'id': '1'});
expect(state.uri.queryParameters, <String, String>{'id': '1'});
return const HomeScreen();
},
),
@ -2607,15 +2607,15 @@ void main() {
path: '/family',
builder: (BuildContext context, GoRouterState state) =>
FamilyScreen(
state.queryParameters['fid']!,
state.uri.queryParameters['fid']!,
),
),
GoRoute(
path: '/person',
builder: (BuildContext context, GoRouterState state) =>
PersonScreen(
state.queryParameters['fid']!,
state.queryParameters['pid']!,
state.uri.queryParameters['fid']!,
state.uri.queryParameters['pid']!,
),
),
],
@ -2819,10 +2819,10 @@ void main() {
name: 'page',
path: '/page',
builder: (BuildContext context, GoRouterState state) {
expect(state.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.location);
expect(state.uri.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.uri.toString());
return DummyScreen(
queryParametersAll: state.queryParametersAll,
queryParametersAll: state.uri.queryParametersAll,
);
},
),
@ -2874,10 +2874,10 @@ void main() {
name: 'page',
path: '/page',
builder: (BuildContext context, GoRouterState state) {
expect(state.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.location);
expect(state.uri.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.uri.toString());
return DummyScreen(
queryParametersAll: state.queryParametersAll,
queryParametersAll: state.uri.queryParametersAll,
);
},
),
@ -2925,10 +2925,10 @@ void main() {
name: 'page',
path: '/page',
builder: (BuildContext context, GoRouterState state) {
expect(state.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.location);
expect(state.uri.queryParametersAll, queryParametersAll);
expectLocationWithQueryParams(state.uri.toString());
return DummyScreen(
queryParametersAll: state.queryParametersAll,
queryParametersAll: state.uri.queryParametersAll,
);
},
),
@ -3913,7 +3913,7 @@ void main() {
initialLocation: '/a',
navigatorKey: rootNavigatorKey,
redirect: (_, GoRouterState state) {
if (state.location.startsWith('/b')) {
if (state.uri.toString().startsWith('/b')) {
return redirectDestinationBranchB;
}
return null;

View File

@ -218,7 +218,7 @@ void main() {
routes: routes,
redirectLimit: 100,
redirect: (_, GoRouterState state) {
lastRedirectLocation = state.location;
lastRedirectLocation = state.uri.toString();
return null;
},
);
@ -287,7 +287,7 @@ void main() {
routes: routes,
redirectLimit: 100,
redirect: (BuildContext context, GoRouterState state) {
if (state.location != '/123/family/345') {
if (state.uri.toString() != '/123/family/345') {
return '/123/family/345';
}
return null;
@ -377,7 +377,8 @@ void main() {
GoRoute(
path: '/abc',
builder: (_, __) => const Placeholder(),
redirect: (BuildContext context, GoRouterState state) => state.location,
redirect: (BuildContext context, GoRouterState state) =>
state.uri.toString(),
),
];
final GoRouteInformationParser parser = await createParser(

View File

@ -41,4 +41,7 @@ void main() {
params: <String, String>{},
queryParams: <String, String>{},
);
state.queryParametersAll;
state.location;
}

View File

@ -10,7 +10,7 @@ void main() {
state.fullPath;
state.pathParameters;
state.matchedLocation;
state.queryParameters;
state.uri.queryParameters;
state.namedLocation(
'name',
pathParameters: <String, String>{},
@ -41,4 +41,7 @@ void main() {
pathParameters: <String, String>{},
queryParameters: <String, String>{},
);
state.uri.queryParametersAll;
state.uri.toString();
}