When building complex applications, you often need to pass more information than what can be neatly included in URL parameters. The go_router
package in Flutter provides the extra
parameter, allowing you to pass additional data (such as complex objects or additional information) along with your navigation.
1. Add Dependencies
First, ensure that you have the go_router
package added to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
go_router: ^6.0.0
Make sure you use the version 6.0.0 otherwise, nested routing might not work. If the version is not correct you will see extra is not going to work with subroutes though.
Steps to Implement
- Set Up go_router:
- Ensure you have the
go_router
package installed in your Flutter project by adding it to yourpubspec.yaml
file.
- Ensure you have the
- Define Routes:
- Create a
GoRouter
instance and define your routes, including nested routes. - Use the
extra
parameter in your route definitions to pass additional data.
- Create a
- Navigating with Extra Data:
- When navigating to a route, include the
extra
parameter to pass additional information. This is done usingcontext.go
orcontext.push
. - Example:
context.go('/details/1', extra: {'info': 'Some additional information for details'})
.
- When navigating to a route, include the
- Accessing Extra Data in the Target Route:
- In the target screen or widget, retrieve the
extra
data from theGoRouterState
. - Cast the
extra
data to the appropriate type to use it effectively.
- In the target screen or widget, retrieve the
- Use the Extra Data:
- Display or use the extra data in your widget to provide a richer user experience.
Set up your routes in a structured way. Here’s an example with nested routes:
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
routes: [
GoRoute(
path: 'details/:id',
builder: (context, state) {
final id = state.params['id']!;
final extraData = state.extra as Map<String, dynamic>?;
final additionalInfo = extraData?['info'];
return DetailsScreen(id: id, additionalInfo: additionalInfo);
},
routes: [
GoRoute(
path: 'subdetails',
builder: (context, state) {
final id = state.params['id']!;
final extraData = state.extra as Map<String, dynamic>?;
final additionalInfo = extraData?['info'];
return SubDetailsScreen(id: id, additionalInfo: additionalInfo);
},
),
],
),
],
),
],
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: ElevatedButton(
onPressed: () {
context.go(
'/details/1',
extra: {'info': 'Some additional information for details'},
);
},
child: Text('Go to Details'),
),
),
);
}
}
class DetailsScreen extends StatelessWidget {
final String id;
final String? additionalInfo;
DetailsScreen({required this.id, this.additionalInfo});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Details for $id')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Details content for $id'),
if (additionalInfo != null)
Text('Additional Info: $additionalInfo'),
ElevatedButton(
onPressed: () {
context.go(
'/details/$id/subdetails',
extra: {'info': 'More details about subdetails'},
);
},
child: Text('Go to Subdetails'),
),
],
),
),
);
}
}
class SubDetailsScreen extends StatelessWidget {
final String id;
final String? additionalInfo;
SubDetailsScreen({required this.id, this.additionalInfo});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Subdetails for $id')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Subdetails content for $id'),
if (additionalInfo != null)
Text('Additional Info: $additionalInfo'),
],
),
),
);
}
}
Consider an application with a HomeScreen
, a DetailsScreen
that shows details based on an ID, and a SubDetailsScreen
nested within DetailsScreen
. You might want to pass additional context or data to these screens that cannot be easily encoded in the URL.
- HomeScreen:
- Navigate to
DetailsScreen
with an ID and additional information usingcontext.go('/details/1', extra: {'info': 'Some additional information for details'})
.
- Navigate to
- DetailsScreen:
- Retrieve and display the ID from the URL parameters and the additional information from the
extra
parameter. - Navigate to
SubDetailsScreen
with the same ID and additional information usingcontext.go('/details/$id/subdetails', extra: {'info': 'More details about subdetails'})
.
- Retrieve and display the ID from the URL parameters and the additional information from the
- SubDetailsScreen:
- Retrieve and display the ID and the additional information passed from
DetailsScreen
.
- Retrieve and display the ID and the additional information passed from
Benefits
- Flexibility: The
extra
parameter allows passing complex objects or additional data that are not suitable for URL parameters. - Cleaner URLs: Keeps URLs clean and focused on primary identifiers, while additional context is passed via
extra
. - Enhanced Navigation: Provides a way to handle more sophisticated navigation scenarios without cluttering your URL structure.
By integrating the extra
parameter into your routing logic, you can manage navigation and state in a more flexible and scalable manner, especially for complex applications with nested routes and varying data requirements.