首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Riverpod:在onPressed中引用ref.watch早先获得的提供者是错误的吗?

Riverpod:在onPressed中引用ref.watch早先获得的提供者是错误的吗?
EN

Stack Overflow用户
提问于 2022-10-24 02:09:17
回答 3查看 38关注 0票数 1

Riverpod文档建议在回调中使用ref.read,就像按钮的onPressed一样,因为您不能在那里使用ref.watch

这样做可以吗?

代码语言:javascript
运行
复制
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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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++ )--这可以确保您正在递增的是提供程序的状态,而不是存储的值。这还会触发小部件的重新构建,因为被监视的状态正在发生变化。

希望这能在我理解的基础上解释你的担忧。

票数 1
EN

Stack Overflow用户

发布于 2022-10-24 07:02:58

我认为这样做是为了保证,我们得到了供应商的最新状态。因此,在(){}中的任何操作之前都应该使用ref.read。这样我们就不可能在将来犯错误了:)

下面是一个可能的情况的完整例子:

代码语言:javascript
运行
复制
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')),
      ],
    );
  }
}
票数 1
EN

Stack Overflow用户

发布于 2022-10-24 02:22:05

ref.readref.watch是不同的:

我们使用ref.read获取提供程序的值一次(一次读取)。

我们使用ref.watch在第一次和每次值更改时获得提供者的值(观察它就像订阅了提供程序一样,因此随时都会收到更改的通知)。

您不需要总是得到值,您应该只获得提供者的值一次。

更新:

我建议您在其他地方使用p,在onPressed函数中使用ref.watch(myProvider).doSomething()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74176115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档