此包恢复了 riverpod 的上下文扩展功能
在 1.0.0 版本中已被弃用。
- 要读取任何 provider,请使用
context.read(myProvider) - 要监听任何 provider,请使用
context.watch(myProvider)
在 riverpod 1.0.0 开发过程中,关于移除上下文扩展曾有过漫长的讨论。
虽然它们非常方便,但它们未能包含在最终版本中有充分的理由。
这不是一个“官方”的 riverpod 包。它旨在与 riverpod 一起使用并提供
官方ConsumerWidget和ConsumerStatefulWidget的替代方案。
入门
这假设您已经设置了 flutter_riverpod (或 hooks_riverpod)。
首先,将 riverpod_context 添加为依赖项。
flutter pub add riverpod_context
接下来,在根 ProviderScope 下方添加 InheritedConsumer
// Before
ProviderScope(
child: MyApp(),
)
// After
ProviderScope(
child: InheritedConsumer(
child: MyApp(),
),
)
就是这样。
上下文扩展
riverpod_context 提供了四个便捷的上下文扩展来与您的 provider 进行交互。
context.read
context.read 可以在任何地方使用,无需任何特殊考虑。
它自然支持任何 provider、provider 系列以及新的 .select() 语法。
Widget build(BuildContext context) {
// this won't rebuild based on 'myValue'
String myValue = context.read(myProvider);
return Text(myValue);
}
context.watch
context.watch 监听 provider,并在 given context 的状态更改时触发该 context 的重建。
它再次支持任何 provider、provider 系列以及
新的 .select() 语法。
Widget build(BuildContext context) {
// this will rebuild each time 'myValue' changes
String myValue = context.watch(myProvider);
return Text(myValue);
}
在使用 context.watch 时有几个重要的注意事项。有了这些,您
也可以安全地使用任何 .autoDispose provider。
1. 仅在 build() 中使用
context.watch 只能在 widget 的 build() 方法中使用。
特别是交互回调 (如 onPressed) 和 StatefulWidget 的 initState、
didChangeDependencies 和其他生命周期处理程序是不允许的。
2. 条件性地监听 provider 时要小心
可以有条件地监听 provider。当 context.watch 可能不会在
每次重建时调用时,就会出现这种情况。
Widget build(BuildContext context) {
if (myCondition) {
return Text(context.watch(myProvider));
} else {
return Container();
}
}
在此示例中,当 myCondition 为 false 时,context.watch 不会被调用。这会导致一个问题
provider 的依赖关系未明确定义。
确保不会发生这种情况很重要,因为这可能导致内存泄漏和错误
行为!
这也是它未能包含在 riverpod 1.0.0 中的主要原因。当然
有一些方法可以防止这种情况,但这取决于用户的责任,因此
不是编译安全的。
然而,防止这种情况相当简单。
如果存在对同一 context 的另一个 context.watch 调用,则此问题已解决。总的来说,
它需要在每次重建时至少有一次 context.watch 调用才能安全。
如果在上面的示例中,myCondition 实际上来自另一个 context.watch 调用,那么您就是安全的。
Widget build(BuildContext context) {
if (context.watch(myConditionProvider)) {
// don't worry about this being called conditionally,
// we already have called context.watch once before
return Text(context.watch(myProvider));
} else {
return Container();
}
}
如果(在某些条件下)没有 context.watch 调用,您必须“预加载”该 context
以获取缺失的 provider。这可以通过简单的 context.prime() 来完成。
在上面的示例中,这可以在 else 语句中完成,或者始终在开始时完成。这样做
多次也没有任何影响。
Widget build(BuildContext context) {
context.prime(); // option 1: always prime
if (myCondition) {
return Text(context.watch(myProvider));
} else {
context.prime(); // option 2: prime to account for missing context.watch call
return Container();
}
}
总而言之,请记住这一点
无论何时有条件地使用 context.watch,请确保要么有另一个无条件的 context.watch,要么在同一 context 上使用 context.prime。
换句话说
如果您在每次重建时总是有至少一次调用 context.watch 或 context.prime,那么您就是安全的。
context.refresh
context.refresh 刷新任何 provider。
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
context.refresh(myProvider);
},
child: const Text('Refresh'),
);
}
context.listen
监听 provider 而不触发重建。
即将推出。