Redux进阶(一)

State的不可变化带来的麻烦

在用Redux处理深度复杂的数据时会有一些麻烦。由于js的特性,我们知道当对一个对象进行复制时实际上是复制它的引用,除非你对这个对象进行深度复制。Redux要求你每次你返回的都是一个全新的State,而不是去修改它。这就要求我们要对原来的State进行深度复制。这往往带来复杂的操作(查找,合并)。一种简单的情况是通过扩展符号或者Object.assign来处理:

这种方式在处理简单的数据来说是比较方便的,但是如果遇到更深一级的数据结构时会显得很无力,而且代码会变得冗长。不仅仅如此,当我们要处理一个包含着对象的数组时,我们要怎么办才好呢?我想,除了深度复制数组然后修改新的数组之外大概没有其他的方法了吧?而且很重要的一点是,如果你对原来整个数组进行了复制,那么绑定了数据的UI会自动渲染,即使它们的数据没有发生变化,简单来说,就是你修改了某一条表格数据,但是界面上整个表格被重新渲染了:

在Redux官方文档中提到了一种解决方案,即范式化数据:概括起来就一句话:减少层级,唯一id索引,用后端建表的方法构建我们的数据结构。其中最重要原则无非是扁平化和关联性。最终我们需要将数据形式转化成以下格式:

按照卤煮的理解,范式化数据无非就是给对象瘦瘦身,再深的层级,我们也尽量将它们扁平化,这样会减少我们对State的查找带来的性能消耗。然后是建立索引表,标识每组数据之间的联系。那么怎么样才能得到我们想要的数据呢?

normalizr方法使用指南

官方最荐normalizr模块,它的用法还是需要时间的去研究的。下面我们就以上面的数据为示例,说明它的用法:

说明:new schema.Entity的第一个参数表示你创建的最外层的实体名称,第二个参数是它和其他新创建的实体的关系,默认是最小的层级,即它只是最后一层,不包含其他层级了。第三个参数里面有个idAttribute,指的是以哪个字段为索引,默认是”id”,它也可以是个参数,返回你自己构造的唯一值,记住,是唯一值。按照这样的套路,你可以随意构建你想要的扁平化数据结构,无论源数据的层级有多深。我们最终都会得到希望的数据结构。

github上有详细的官方文档可供查找,卤煮在此只是简单的说明一下用法,诸位可以仔细观察文档上的用法,不需要多少时间就可以熟练掌握。到此为止,万里长城,终于走完了第一步。

如何将范式化数据后再次转化

什么?好不容易转化成自己想要的数据结构,还需要再次转化吗?很遗憾告诉你,是的。因为范式化后的数据只便于我们在维护Redux,而界面业务渲染的数据结构往往跟我们处理后的数据是不一样的,举个栗子:bootstrap或者ant.design的表格渲染数据结构是这个样的:

因而在界面引用State上的数据时,我们需要一个中介,把范式化的数据再次转化成业务数据结构。我相信这个步骤十分简单,只需要写一个简单的转换器就行了:

如果你在mapStateToProps里面断点调试,你会发现每一次dispatch都会强行执行mapStateProps方法保证对象的最新状态(除非你引用的是基础类型数据),因此,不管界面的操作是如何,被connect数据都会被强行执行一次,虽然界面没有变化,但是显然,js的性能会有折扣,尤其是对深度对象的复杂处理。因此,官方推荐我们创建可记忆的函数高效计算Redux Store里面的衍生数据。

Reselect方法使用指南

我在这里做了个耍了点花样,你可以看到,我是按照table.data这个数组来查找界面业务数据的。这种操作可以使得我们只需要关心table.data这个简单的一维数组,在删除或者添加一条数据的时候显得尤为有用。

我们最后为了计算state,引用了dot-prop-immutable模块,他是immutable的扩展,对于数据计算非常高效。我接着使用了另外一个dot-prop-immutable-chain模块,它增加了dot-prop-immutable的链式用法。关于dot-prop-immutable的用法卤煮不再详细说明,在后面给出的例子中一眼就能看明白,而且官方文档上也有详细说明。下面我们通过一个表格增删查改来实际展示我们这次的解决方案。

瞧,我们展示了整个reducer,相信它已经变得容易维护得多了,并且由于使用了范式化数据结构以及immutable的扩展模块,不仅仅提升了计算性能,减少界面的的渲染,而且还符合Redux的State不可修改的原则。

结束语

React+Redux组合在实际应用过程中需要优化的地方还很多,这里只是简单展示其中的一个小点。虽然在计算dom界面变化时React已经做得足够好,但并不意味着我们可以不用为界面渲染问题背锅,React肩负了多数界面更新计算的任务,而让前端开发人员更多地去处理数据,因此,我们可以在这里层多花点时间把项目做好。

参考资料

 Redux中文文档

把你的redux store 组织成数据库形式

normalizr在GitHub上的地址

reselect在GitHub上的地址

dot-prop-immutable在GitHub上的地址

1 收藏 1 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
  • zhiqiang21 前端工程师 08/29

    Redux是要求每次都返回一个全新的state “这就要求我们对原来的State进行深复制”。这句有问题吧,将修改的state直接返回就好了为什么要深复制。况且Object.assign对对象深层次的数据本来就是浅复制。

跳到底部
返回顶部