Widgets not updating when modifying a Riverpod Provider from outside the UI
The docs are somewhat misleading in this case. It is true that you can access a Provider
without the context in that way, but you are also instantiating a new ProviderContainer
which is where the state of all of your providers is stored. By doing it this way, you are creating then modifying a new Notifier
; which means the Notifier
your widgets are listening to is left untouched.
One way you could use a provider outside the widget tree is to declare your ProviderContainer
outside the ProviderScope
. Be careful with this as it could lead to unintended consequences.
Replace your main.dart
code with this:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
//Provider container which holds the state of all my providers
//This would normally be inaccessible inside of the ProviderScope
final providerContainer = ProviderContainer();
//A function that accesses and uses myNotifierProvider ***Without needing a context***
void incrementCountWithoutContext() {
var provider = providerContainer.read(myNotifierProvider);
provider.incrementCount();
}
final myNotifierProvider = ChangeNotifierProvider((_) {
return MyNotifier();
});
class MyNotifier extends ChangeNotifier {
int count = 0;
void incrementCount() {
count++;
notifyListeners();
}
}
void main() {
runApp(
//Here is where we pass in the providerContainer declared above
UncontrolledProviderScope(
container: providerContainer,
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final _provider = watch(myNotifierProvider);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'${_provider.count}',
style: Theme.of(context).textTheme.headline4,
),
ElevatedButton(
//Increment count by accessing the provider the usual way
onPressed: _provider.incrementCount,
child: Text('Increment count the usual way'),
),
ElevatedButton(
//Increment the count using our global function
//Notice no context is passed to this method
onPressed: incrementCountWithoutContext,
child: Text('Increment count without context'),
)
],
),
),
);
}
}
Chrispy11
Updated on November 28, 2022Comments
-
Chrispy11 over 1 year
I'm trying to update a value inside my Provider from outside the UI, as described in the docs:
final container = riverpod.ProviderContainer(); AppProvider _appProvider = container.read(appProvider); _appProvider.setMode(true);
Inside my setMode method I call notifyListeners(). Now the problem is that my Widgets don't rebuild, even though the value in my provider successfully changed and notified its listeners. The widgets are listening like this:
riverpod.Consumer(builder: (context, watch, child) { AppProvider _appProvider = watch(appProvider); ...
When updating the provider from inside the UI, the widgets are rebuild as expected.
What do I have to do to make my UI rebuild correctly in this case aswell?
-
Chrispy11 about 3 yearsI see, as I understood the main selling point of Riverpod was the possibility to access providers from anywhere, but I guess this is not entirely true and only useful for testing. Doing it the way you showed works! But probably not something we are supposed to do then I guess. Might as well stick with Provider then.
-
Rémi Rousselet about 3 years@Chrispy11 Riverpod never claimed that you can access providers "everywhere". In fact, it is a feature that you can't. Otherwise that'd just be a global variable, which is bad for maintainability. The code given here is correct (although I would advise against having the
ProviderContainer
as a global variable). -
Vayth about 3 years@RémiRousselet, Do you have any advice on how calling the the provider outside the ui, if not for using global
ProviderContainer
variable? For once, I need to call it from outside the ui forFirebaseMessaging
background message. -
ajonno almost 3 yearsI'd like to know this too - did you get any reply ?
-
SalahAdDin almost 2 years@Vayth did you solve it?