从 UI 外部修改 Riverpod 提供程序时小部件不更新

时间:2021-01-30 13:51:05

标签: flutter provider riverpod

我正在尝试从 UI 外部更新我的 Provider 中的值,如文档中所述:

final container = riverpod.ProviderContainer();
AppProvider _appProvider = container.read(appProvider);
_appProvider.setMode(true);

在我的 setMode 方法中,我调用了 notifyListeners()。现在的问题是我的小部件不会重建,即使我的提供者中的值成功更改并通知了它的听众。小部件是这样监听的:

riverpod.Consumer(builder: (context, watch, child) {
    AppProvider _appProvider = watch(appProvider);
...

当从用户界面内部更新提供程序时,小部件会按预期重建。

在这种情况下,我还需要做什么才能正确重建 UI?

1 个答案:

答案 0 :(得分:0)

在这种情况下,文档有些误导。确实,您可以通过这种方式在没有上下文的情况下访问 Provider,但您也在实例化一个新的 ProviderContainer,它是存储所有提供程序状态的位置。通过这样做,您正在创建然后修改一个新的 Notifier;这意味着您的小部件正在收听的 Notifier 保持不变。

您可以在小部件树之外使用提供程序的一种方法是在 ProviderContainer 之外声明您的 ProviderScope。请注意这一点,因为它可能会导致意想不到的后果。

将您的 main.dart 代码替换为:

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'),
            )
          ],
        ),
      ),
    );
  }
}