Reputation: 33
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?
Upvotes: 3
Views: 6739
Reputation: 1172
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'),
)
],
),
),
);
}
}
Upvotes: 3