Riverpod文档建议在回调中使用ref.read
,就像按钮的onPressed
一样,因为您不能在那里使用ref.watch
。
这样做可以吗?
build(context, ref) {
// Use ref.watch ahead of time, because I refer to p all over
// the widget tree. p is a mutable ChangeNotifier
final p = ref.watch(myProvider);
return ElevatedButton(
onPressed: () {
// Refer to provider obtained via ref.watch earlier
p.mutateSomehow(),
},
child: /* huge tree referring to p 20 times */
);
}
?我在我所有的代码中都这样做,它看起来工作得很好,但是如果这个模式还好的话,似乎Riverpod只是推荐它,并且不推荐ref.read
。
发布于 2022-10-24 04:05:45
假设您有如下定义的提供程序:final pProvider = StateProvider<int>((ref)=> 0);
在您的构建中,您可以这样观察它的值:final p = ref.watch(pProvider.state).state;
现在,构建中的p
是提供程序的存储值。
在回调中,如果您想要增加p
的值,只需说p++
或p + 1
,就可以做到这一点,这意味着您只是在递增获取的值,而不是提供者本身的状态。当您想要获取提供程序的值,然后在将其保存到数据库之前向其添加一些内容时,这主要是一种场景。
另一方面,如果要更改由ref.watch
方法监视的提供程序的状态,则必须像这样增加状态提供程序( ref.read(pProvider.notifier).state++
)--这可以确保您正在递增的是提供程序的状态,而不是存储的值。这还会触发小部件的重新构建,因为被监视的状态正在发生变化。
希望这能在我理解的基础上解释你的担忧。
发布于 2022-10-24 07:02:58
我认为这样做是为了保证,我们得到了供应商的最新状态。因此,在(){}中的任何操作之前都应该使用ref.read
。这样我们就不可能在将来犯错误了:)
下面是一个可能的情况的完整例子:
void main() => runApp(const ProviderScope(child: MyApp()));
final indexProvider = StateProvider<int>((ref) {
ref.listenSelf((previous, next) {
print(ref.controller.state);
});
return 0;
});
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
print('build $MyApp');
return MaterialApp(
home: Center(
child: Column(
children: const [
SizedBox(height: 50.0),
ButtonInternalState(),
SizedBox(height: 50.0),
ButtonProviderState(),
],
),
),
);
}
}
class ButtonInternalState extends ConsumerWidget {
const ButtonInternalState({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
print('build $ButtonInternalState');
// Once upon a time, all we had to do was read the data once and not keep track of anything
final StateController<int> indexState = ref.read(indexProvider.state);
return ElevatedButton(
onPressed: () => indexState.state++,
// It would have avoided the mistake
// onPressed: () => ref.read(indexProvider.state).state++,
child: Text('The state our wrong provider - ${indexState.state}'),
);
}
}
class ButtonProviderState extends ConsumerWidget {
const ButtonProviderState({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
print('build $ButtonProviderState');
final int index = ref.watch(indexProvider);
return Column(
children: [
ElevatedButton(
onPressed: () => ref.read(indexProvider.notifier).state++,
child: Text('Here changes state the provider - $index')),
ElevatedButton(
onPressed: () => ref.refresh(indexProvider),
child: const Text('Refresh our provider')),
],
);
}
}
发布于 2022-10-24 02:22:05
ref.read
和ref.watch
是不同的:
我们使用ref.read
获取提供程序的值一次(一次读取)。
我们使用ref.watch
在第一次和每次值更改时获得提供者的值(观察它就像订阅了提供程序一样,因此随时都会收到更改的通知)。
您不需要总是得到值,您应该只获得提供者的值一次。
更新:
我建议您在其他地方使用p
,在onPressed
函数中使用ref.watch(myProvider).doSomething()
。
https://stackoverflow.com/questions/74176115
复制相似问题