在项目里我们最好还是遵循数据不可变性,即更新状态时,不在 old 状态上修改,而是在 old 状态的基础上拷贝一份新的,在新状态上进行修改,并返回新状态!!!
而且在使用 Redux 管理状态时,我们在 reducer 函数中进行状态更新时,是不允许我们直接在 old 状态上修改的,而是需要我们返回拷贝+更新过后的新状态!!!
<1> 使用扩展运算符... 进行拷贝
并不能实现完全的深拷贝,只是比浅拷贝多复制了一层
缺点:
- 即如果要拷贝的对象中有属性的值是对象的话,那么对该属性的拷贝还是浅拷贝,即还是拷贝的是对该属性值的对象的引用!!
<2> 使用 json--parse json--stringify
确实能实现完全的深度拷贝
缺点:
- 但是不能有 undefined ,即如果遇见值为 undefined ,就会自动把该值 pass 掉,不会对该值进行复制!!!
<3> 手动进行 deepcopy
手动进行递归复制,一层一层的复制!!
缺点:
- 性能不好,且占用内存!!
<4> Immutable
一个第三方库:
实现原理是
Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变,同时为了避免 deepCopy 把所有的节点都复制一遍带来的性能损耗,Immutable库使用了Structural Sharing(结构共享),及如果对象树种一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享!!!
如下图所示:
(1) 引入 Immutable
- npm i immutable
- import {Map} from 'immutable '
(2) Immutable 常用类型
1 . Map
Map 类型适用于原始数据为对象的转换
使用方法为,用Map() 方法包括要转换的原始数据即可。需要注意的是:
- 如果要转换的对象里面也存有对象值的话,就也需要把存的对象值也用Map() 包括!!!
- 因为
Immutable库使用了Structural Sharing(结构共享),所以如果对象中存储的对象内容不改变的话,那么新旧状态会共同引用同一个存的对象值,可以利用该点,来避免不必要的渲染!!!提供性能!!!
- 修改的话,使用set() 方法,可以连续调用!!
- 获得状态的话,使用get() 方法
- 把
Immutable类型的数据转换为普通 JS 对象,用**immutable.toJS()**方法!!!
2 . List
Map 类型适用于原始数据为数组的转换
使用方法,跟封装的数据方法一样!!
3 . 不依赖类型,只需要依赖两个方法
上述的两个类型,Map 和 List 都是在我们已经知道原始数据类型是对象 or 数组时才使用的,但如果我们不知道,有没有一种通用的方法呢?
fromJS(o) 和toJS():
-
使用该方法后,如果被转换的对象中存有值为对象or数组的属性,也会自动将它们转换为对应的 Map or List 类型
-
修改状态,一级修改的话,set("","") or setIn(),方法
- 两级修改,即修改对象中的对象时,用**setIn([] , "")** ,第一个参数采用数组模式,表明修改 n 级中的那个属性 - 两极修改,如果是修改对象中的数组,就用下标代表要修改哪个!!
-
增加or删除状态,用 updateIn([] , callback)
- 在第一个参数中,选中要修改的属性 - 第二个参数,回调函数中返回修改后的状态