图1Written by Neil Fenton16 June 2016
原文请见
React和Redux组合是非常棒的,当他们两个一起使用时,可以帮助我们在程序结构中分离关注点.即使React易用性非常强,但是总会遇到高性能需求的时间.
在React中最昂贵的操作就是渲染回路.当组件检测到输入的变化,渲染回路就会被触发(译注:这里的意思的组件的action会改变redux的state,变回最终又回到组件了).
当我们初次开始React程序的时候,我们不会担心渲染回路的花销问题.但是当我们的UI变得复杂的时候,我们需要考虑这一点.React提供了一些工具让我们能劫持渲染回路,如果渲染看上去不必要,我们就可以使用工具来阻止重渲染的发生.为了这么做,我们要敲入componentShouldUpdate
生命周期事件,返回一个布尔值,通知组件是否应该进行更新.这是以PureRenderMixin
作为基础,它比较输入的props和state和先前的props和state,如果两者相等就返回false.
这个生命周期事件和Immutable集合一起可以实实在在的改进性能,因为我们可以很容易的决定是渲染还是不渲染组件.
不幸的是,仅此而已.
考虑到紧接着的问题:我们构建一个购物车,有三个输入类型:
- 购物车里的货物
- 货物的数量
- 相应的税率(基于州或者省)
问题是无论只要输入的状态一改变(新货物加入,数量的变化,选择州的变哈),每一个部分都要被重新计算和渲染.如果我们的购物车里有几百个东西,你可以想象一下这将会是一个很大的性能问题.改变税率肯能会触发购物车的重新计算,但是是不应该发生的.税率的变化仅仅会影响衍生的数据.仅仅总数,税的总数应该发生变化,并且发生后继的更新.接下来我们看看怎么修复这个问题.(译注:这段的意思是如果税率变化,在UI组件中是不应该发生渲染的,只有几个地方需要发生变化)
Reselect前来救援
Reselect用来记忆selectors的库.我们定义的selectors是作为函数获取Redux state的某一部分.使用记忆能力,我们可以组织不必要的衍生数据的重渲染和计算过程,由此加速了我们的app.
考虑下面这个示例:
如果我们有几百甚至上千个条目,渲染购物车中的所有项目花费会非常的大,即使是税率的变化.用户每一次搜索的他的购物车的时候,我们是否应该一遍一遍的重计算?我们可以使用记忆性的selectors来阻止昂贵的计算过程.使用记忆selectors,如果Redux中的state的树很大,我们也不用担心没吃state变化的计算问题.我们也可以在前端增加额外的灵活性,把这些selectors分散到单个的组件中.
现在看看一个使用Reselect的简单selector:
selector using Reselect
在上面的实例中,我们把item的获取函数分成两个函数,第一个函数(第3行)简单的额获取购物车中所有的items,第二个函数代表一个记忆性selector.Reselect暴露了createSelector
API,我们可以借此创建一个记忆性的selector.这个意思是getItemWithTotals
在第一次函数运行的时候将会进行运算.如果同一个函数再次被调用,但是输入值(getItems
的值)没有变化,函数将会返回一个缓存(cached)的计算结果.如果items被修改了(例如:item添加,数量的变化,任何事情操作了getItems
的结果),函数将会再次执行.
这是一个非常有力的概念,允许我们在一个组件的state需要重计算的时候,完全的优化应该被渲染的组件.这意味着我们不在担心getItems
和后继的每一次中价格的计算,但操作的时候,不会影响state的执行.
我们继续这个方式来创建四个衍生数据的selectors.包括小计,税额总计和总价格.
四个selectors
使用selector
selectors代码完成以后,让我们看看怎么在组件中使用getItemWithTitals
selector:
现在我们有了有了一个组件,仅仅感知购物车中的items.这是一个不错的方式因为它和总计和小计没有任何关联.他不是可以重用的组件,但是是性能非常好的组件.和这个组件无关的变化不会引起额外的重渲染.
这个方式应用到其他的购物车上意味着我们将会有一个组件负责显示小计,总计和税额计算.
早一点在应用中使用这些优化措施意味着未来需要修正性能问题的时候做的工作就比较少.我建议尽可能早的使用reselect.在组件之外使用Selectors意味着我们可以容易的测试这些数据衍生计算.在Redux中使用简单的模拟数据,基于提供的数据测试期待的输出结果.
进一步了解这些概念,参考demo
网友评论