immutable 和 React 的那些事儿
immutable 的中文意思叫做不可改变的,那不可改变的数据结构有什么优势呢?它与 React 会擦出什么样的火花呢?它底层又是如何实现的呢?我们接下来一起来看。
# 为什么要 immutable
我们在书写代码的时候可能会做出这样的操作:
function sortMyArray(arr) {
arr.sort((a, b) => a - b);
// ...
}
2
3
4
我们虽然能够得到正确的结果,但是非常遗憾的是这个数组被我们改变了,他经过我们的函数被污染了,再使用到其他地方就可能得到意想不到的结果。
所以在平常的开发过程中,我们要有 immutable 的意识。
那么为什么我们说 immutable 适合 react 呢?我们接着看。
# immutable 和 react
众所周知,React 更新方式是由 state
和 props
的更新引起的,当某个组件发生更新的时候,React 会根据最新的状态构建一颗新的 virtual DOM
树,然后使用 diff 算法进行对比,如果不同则会进行渲染。
React 中 shouldComponentUpdate
默认返回 true
,所以当更改某一个叶子节点的状态时,整个树形都会重新渲染,即使是那些状态没有更新的节点,这在某种程度上耗费了性能。
基于这些问题 React 又提出了 PureComponent
,它实现了对数据进行了浅比较,虽然这解决了一部分问题,但是还是没有根本性的解决这个问题。
比如说,数据是这样变动的:
[{ name: 'pre', data: {} }][
// =====> 只改变了 name 属性
{ name: 'after', data: {} }
];
2
3
4
这样的数据改变并没有引起组件的更新,这显然是不对的,这是因为这两个对象的引用是相同的,同时数组长度也相同。
那么,我们要如何解决这个问题呢?
- 深拷贝:改变了引用地址,自然就会更新了,但是太消耗内存。
- JSON.stringify: 这也是深拷贝的一种黑魔法了,有局限性,会断掉原型链,同时有些东西并不能使用这种方式拷贝,比如函数。
接下来我们要说的就是 immutable.js 了,虽然实现 immutable 的库比较多,但这里就挑一个来说。
它的特点就是 持久化数据结构
和 结构共享
,保证每一个对象都是不可变的,任何添加、删除、修改等操作都会返回一个新的对象,并且通过结构共享提高性能。
比如说,我们在一个对象中新增加一个节点,那么就把这个对象到根节点的路径上的节点全部重新生成,而其余的结构不变,这样整个对象的引用改变了,但是却只修改一部分数据,大大提高了性能。
# immutable 如何实现
immutable.js 参考了 Vector Trie
这种数据结构,使用了位分区的方式,同时加上哈希表来实现的。
具体的分析可以看这篇文章,我这儿就不多解释了。