How to avoid boilerplate code in Flutter when changing routes and keeping the providers?
I have already solved this problem, but I want to clean the code so it's easier to maintain.
The problem was: When using data that comes from Provider<T>
, how can I make the providers and their data available in the next view when Navigator.of(context).push
?
I solved it with this code:
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) {
return MultiProvider(
providers: [
Provider<User>.value(value: context.read<User>()),
Provider<Computer>.value(value: context.read<Computer>()),
],
builder: (_, __) => const TheNextScreen(),
);
},
fullscreenDialog: true,
),
);
This works properly, but I'm concerned about a few points:
- Is this a good design pattern? Or does it look like an anti-pattern? Is there a better way to do it?
- If I type
context
instead of_
, I'd end up overwriting the originalcontext
variable and use acontext
that does not have the providers, therefore increasing the risk of errors in the future (e.g. by calling.read
on the incorrectcontext
). - I saw some other questions and some people used
ChangeNotifierProvider
instead (Flutter Provider nested navigation). This seems like an OK solution and I know how to useChangeNotifierProvider
, but as far as I know it doesn't allow a clean way to pass an array of providers, soMultiProvider
was my choice.
If there's any way to improve this code design (for example, related to the above concerns), that'd be a helpful answer.
Author of Provider here
This problem arises only when you're trying to scope providers (aka having a provider only available for one screen).
A much simpler solution is to not scope the provider at all. Place your providers above MaterialApp
:
MultiProvider(
providers: [...],
child: MaterialApp(...),
)
This way, you won't need to add those providers again when using Navigator.push, since the new route would already have access to them.