redux 是否在对商店进行任何更新时评估商店的所有侦听器?

dav*_*ler 9 javascript reactjs redux react-redux easy-peasy

据我所知,当商店中的任何内容发生变化时,redux 都会通知所有订阅者到商店,无论是订阅深层嵌套的叶子还是订阅顶级状态。

在您遵循指导原则的应用程序中:

许多单独的组件应该连接到商店而不是仅仅几个...... [文档]

您最终可能会遇到很多听众和潜在的性能问题?

免责声明:我了解选择器函数只会在选择器函数的结果发生变化时导致重新渲染。我明白,仅仅因为监听器函数被评估,并不意味着订阅组件会重新渲染。我知道评估选择器函数比反应组件渲染相对便宜。

但是,我只是想确认这确实是 redux 的工作原理吗?

例如给出以下示例侦听器

const result = useSelector(state => state.a.b.c.d.e.f.g.h.i.j.k)
Run Code Online (Sandbox Code Playgroud)

如果我们沿其他路径更新其他值,则与上述侦听器无关,例如

const exampleReducer = (state) => {
   return { ...state, asdf: 'asdf' }
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,所有监听器,包括上面的例子,都会被调用。

对于上下文,我的实际用例是我使用的是基于 redux 的https://easy-peasy.now.sh/。需要明确的是,我在生产中没有任何与绑定太多侦听器相关的当前性能问题。然而,每次我通过useStoreState钩子附加一个侦听器时,我想知道是否应该最小化绑定另一个侦听器到商店。

另外,如果你好奇,受到这种想法的启发,我实现了一个状态树,它只通知相关的听众

也许这是对状态库的过早优化......但如果是这样,为什么?是否假设使用 redux 的应用程序将具有简单快速的选择器并且应用程序瓶颈将在其他地方?

mar*_*son 8

我是 Redux 维护者和 React-Redux v7 的作者。其他几个答案实际上非常好,但我想提供一些额外的信息。

是的,Redux 存储将始终store.subscribe()在每个分派操作后运行所有侦听器回调。然而,这并不意味着所有 React 组件都会重新渲染。根据您的useSelector(state => state.a.b.c.d)示例,useSelector当前选择器结果与前一个选择器结果进行比较,并且仅在值已更改时强制此组件重新渲染。

我们建议“连接更多组件以从 Redux 读取”的原因有多种:

  • 每个组件将从 Redux 存储中读取一个较小的范围值,因为它关心的整体数据较少
  • 这意味着在给定操作后将被迫重新渲染的组件更少,因为实际上更新此特定数据的可能性较小
  • 相反,这意味着您不会遇到这样的情况:一个大型父组件一次读取多个值,总是被迫重新渲染,因此总是导致其所有子组件也重新渲染。

因此,真正的问题不是侦听器回调的数量——而是这些侦听器回调做了多少工作,以及有多少 React 组件因此被迫重新渲染。总的来说,我们的性能测试表明,更多的监听器读取更少的单个数据会导致更少的 React 组件被重新渲染,并且更多监听器的成本明显低于渲染更多 React 组件的成本。

有关更多信息,您应该阅读我关于 React 和 React-Redux 如何工作的帖子,这些主题详细介绍:

您可能还想阅读讨论 React-Redux v7 开发的 Github 问题,其中我们放弃了在 v6 中使用 React Context 进行状态传播的尝试,因为它的性能不够好,并返回使用直接存储订阅v7 中的组件。

但是,是的,您提前过多担心性能。React 和 React-Redux 的行为方式有很多细微差别。实际上,您应该在生产环境中对自己的应用程序进行基准测试,以查看是否确实存在任何有意义的性能问题,然后进行适当的优化。