Chrispy11
Chrispy11

Reputation: 33

Widgets not updating when modifying a Riverpod Provider from outside the UI

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

Answers (1)

mskolnick
mskolnick

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

Related Questions