Why Pass Arguments?
In any non‑trivial app, you'll need to send data from one screen to another when the user navigates. For example, tapping a product in a list should take you to a detail screen that knows which product to display. Flutter's Navigator allows you to pass arguments in several ways, from simple primitive values to complex objects. This guide covers the most common patterns for passing data between screens.
Passing Arguments with MaterialPageRoute
When pushing a new route using MaterialPageRoute, you can include an arguments parameter in the route's settings. The settings object holds metadata about the route, including arguments.
Extracting Arguments in the Destination Screen
In the destination widget, you can retrieve the arguments using ModalRoute.of(context). This gives you the current route, from which you can access the settings.arguments.
You should cast the argument to the expected type. Always handle cases where the argument might be missing or of the wrong type.
Passing Complex Objects
You can pass any object as an argument – a Map, a custom class, or even a function. For custom classes, it's a good practice to make them immutable and possibly implement toString for debugging. For example:
Named Routes with Arguments
If you use named routes (defined in MaterialApp's routes), you can pass arguments by using Navigator.pushNamed with a separate arguments parameter.
With onGenerateRoute, you can handle dynamic route names (e.g., /product/123) as well. For that, you'd parse the route path to extract the ID. However, for simplicity, using arguments is often sufficient.
Returning Data Back to the Previous Screen
When you pop a route, you can also return data to the previous screen using Navigator.pop(context, result). The previous screen can wait for the result with await Navigator.push(...).
Common Mistakes
- Forgetting to cast: Always cast the arguments to the expected type. Use
asand handle potential type errors.
- Forgetting to cast: Always cast the arguments to the expected type. Use
- Not checking for null: The arguments might be null if the route was created without arguments. Use null checks or provide default values.
- Passing mutable objects: If you pass a mutable object, changes in the destination screen might affect the original (if you later modify it). Consider making objects immutable or passing copies.
- Using
settings.argumentswithout casting: This returnsObject?, so you must cast it to the correct type.
- Using
- Not handling edge cases: If the argument type is wrong, your app will crash. Validate or use
if (args is String)before casting.
- Not handling edge cases: If the argument type is wrong, your app will crash. Validate or use
Best Practices
- Use a dedicated model class to pass complex data.
- For large or sensitive data, consider using a state management solution (like Provider, Riverpod) instead of passing through routes.
- When using named routes with arguments, consider using
onGenerateRouteto centralize argument parsing.
- When using named routes with arguments, consider using
- Always document what arguments a screen expects (e.g., using comments).
- Use
constfor route arguments that are constant values.
- Use
Key Takeaways
- Arguments are passed via
RouteSettings.argumentsinMaterialPageRoute.
- Arguments are passed via
- Retrieve arguments in the destination using
ModalRoute.of(context)!.settings.arguments.
- Retrieve arguments in the destination using
- You can pass any object, including custom classes, as arguments.
- Named routes also support arguments through
Navigator.pushNamedandonGenerateRoute.
- Named routes also support arguments through
- Use
await Navigator.pushandNavigator.popto return data back to the previous screen.
- Use
- Always cast and handle potential null or type mismatches to avoid runtime errors.