从 UI 外部修改 Riverpod Provider 时小部件不更新
Widgets not updating when modifying a Riverpod Provider from outside the UI
我正在尝试从 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 更新提供程序时,小部件按预期重建。
在这种情况下,我需要做什么才能使 UI 正确重建?
在这种情况下,文档有些误导。的确,您可以通过这种方式在没有上下文的情况下访问 Provider
,但您也在实例化一个新的 ProviderContainer
,这是存储所有提供者状态的地方。通过这种方式,您正在创建然后修改一个新的 Notifier
;这意味着 Notifier
您的小部件正在收听的内容保持不变。
您可以在小部件树之外使用提供程序的一种方法是在 ProviderScope
之外声明您的 ProviderContainer
。请小心,因为它可能会导致意想不到的后果。
将您的 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'),
)
],
),
),
);
}
}
我正在尝试从 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 更新提供程序时,小部件按预期重建。
在这种情况下,我需要做什么才能使 UI 正确重建?
在这种情况下,文档有些误导。的确,您可以通过这种方式在没有上下文的情况下访问 Provider
,但您也在实例化一个新的 ProviderContainer
,这是存储所有提供者状态的地方。通过这种方式,您正在创建然后修改一个新的 Notifier
;这意味着 Notifier
您的小部件正在收听的内容保持不变。
您可以在小部件树之外使用提供程序的一种方法是在 ProviderScope
之外声明您的 ProviderContainer
。请小心,因为它可能会导致意想不到的后果。
将您的 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'),
)
],
),
),
);
}
}