reactjs – 如何避免使用重新选择来计算派生状态时React重新渲染

我在我的应用程序中使用了React Redux Reselect Immutable.js的最终组合.我喜欢重新选择的想法,因为它让我保持我的状态(由减速器维护)尽可能简单.我使用一个选择器来计算我需要的实际状态,然后将其提供给React组件.

这里的问题是,一次reducers的一个小变化会导致选择器重新计算整个派生输出,结果整个React UI也会更新.我的纯组件不起作用.这很慢.

典型示例:我的数据的第一部分来自服务器,基本上是不可变的.第二部分由客户端维护,并使用redux操作进行变更.它们由单独的减速器维护.

我使用选择器将两个部分合并到一个记录列表中,然后传递给React组件.但显然,当我在其中一个对象中更改单个内容时,将重新生成整个列表并创建新的Records实例. UI完全重新渲染.

显然每次运行选择器并不是完全有效但仍然相当快,我愿意做出这种交易(因为它确实使代码更简单,更清晰).问题是实际渲染很慢.

我需要做的是将新选择器输出与旧选择器输出深度合并,因为Immutable.js库足够聪明,不会在没有任何更改时创建新实例.但由于选择器是无法访问先前输出的简单功能,我想这是不可能的.

我认为我目前的做法是错误的,我想听听其他想法.

可能的方法是在这种情况下摆脱重新选择并将逻辑移动到reducers的层次结构中,该层次结构将使用增量更新来维持所需的状态.

我解决了我的问题,但我猜没有正确的答案,因为它真的取决于具体的情况.就我而言,我决定采用这种方法:

原始选择器处理得很好的挑战之一是最终信息是从以任意顺序传递的许多部分编译而来的.如果我决定逐步在Reducer中构建最终信息,我必须确保计算所有可能的场景(信息块可能到达的所有可能的顺序)并定义所有可能状态之间的转换.然而,通过重新选择,我可以简单地拿走我现在拥有的东西并从中取出一些东西.

为了保持这个功能,我决定将选择器逻辑移动到包装父减速器中.

好吧,让我们说我有三个减速器,A,B和C,以及相应的选择器.每个处理一条信息.该部分可以从服务器加载,也可以来自客户端的用户.这将是我原来的选择器:

const makeFinalState(a,b,c) => (new List(a)).map(item => 
  new MyRecord({ ...item,...(b[item.id] || {}),...(c[item.id] || {}) });

export const finalSelector = createSelector(
  [selectorA,selectorB,selectorC],(a,c) => makeFinalState(a,c,));

(这不是实际的代码,但我希望它有意义.请注意,无论各个reducer的内容可用的顺序如何,选择器最终都会生成正确的输出.)

我希望我的问题现在很明确.如果任何这些reducer的内容发生变化,则从头开始重新计算选择器,生成所有记录的全新实例,最终导致React组件的完全重新呈现.

我目前的解决方案看起来很简单

export default function finalReducer(state = new Map(),action) {
  state = state
    .update('a',a => aReducer(a,action))
    .update('b',b => bReducer(b,action))
    .update('c',c => cReducer(c,action));

  switch (action.type) {
    case HEAVY_ACTION_AFFECTING_A:
    case HEAVY_ACTION_AFFECTING_B:
    case HEAVY_ACTION_AFFECTING_C:
      return state.update('final',final => (final || new List()).mergeDeep(
        makeFinalState(state.get('a'),state.get('b'),state.get('c')));

    case LIGHT_ACTION_AFFECTING_C:
      const update = makeSmallIncrementalUpdate(state,action.payload);
      return state.update('final',final => (final || new List()).mergeDeep(update))
  }
}

export const finalSelector = state => state.final;

核心思想是:

>如果发生了重大事件(即我从服务器获得了大量数据),我将重建整个派生状态.
>如果发生了一些小的事情(即用户选择了一个项目),我只是在原始的reducer和包装父减速器中进行快速增量更改(存在一定的重复性,但是必须实现一致性和良好的性能) .

与选择器版本的主要区别在于我总是将新状态与旧状态合并. Immutable.js库非常智能,如果它们的内容完全相同,则不会用新的Record实例替换旧的Record实例.因此保留了原始实例,因此不会重新呈现相应的纯组件.

显然,深度合并是一项代价高昂的操作,因此这对于非常大的数据集不起作用.但事实是,与React重新渲染和DOM操作相比,这种操作仍然很快.因此,这种方法可以在性能和代码可读性/简洁性之间做出很好的折衷.

最后的注意事项:如果不是单独处理那些轻量级动作,那么这种方法基本上等同于用纯组件的shouldComponentUpdate方法中的deepEqual替换shallowEqual.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom