为什么存在Immutable data
JavaScript 中的对象一般是可变的,因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。
例:当你打印原始的A时,你会发现
虽然这样做可以节约内存,但当应用复杂后,数据会变得很不好操控。为了解决这个问题,一般的做法是使用浅拷贝或深拷贝来避免被修改,但这样会造成内存的浪费。
什么是Immutable data
Immutable Data就是一旦创建,就不能再被更改的数据。对Immutable对象的任何增删改操作都会返回一个新的 对象,且旧对象不变。Immutable可以很好的避免深拷贝遍历节点带来的性能损耗,它运用了结构共享原则,即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
浅谈immutable React
reacr的浅复制
this.state = { label : 1, value : "ccc"}...render( const { label, value } = this.state; return(label: { label }, value: { value }))
const 就是一次浅复制,通常用于在渲染的时候提供一些变化的值,这样不需要我们在render中对某个变量进行其他操作。所以在明确只是浅复制的情况下,尽量使用const定义变量,因为const定义的变量不能被赋值或更改,这样就可以避免不小心改变了该变量而引起问题。浅复制的好处就是可以有效的节约内存地址,避免不必要的内存浪费。
this.state = { value: { a: 1 }}const { value } = this.state;//浅复制value.a = 2;console.log(this.state.value.a);//输出2,但dom不更新this.setState({ value });//dom更新
这里 value.a = 2 虽然已经改变了state中value的值,但由于是浅复制,新旧value指向的是同一块内存地址,组件更新时(state,props改变)默认只比较新旧对象的内存地址是否一致,如果一致则不更新。同理,如果在reducer中,直接对当前的state进行修改并返回props,相应的调用该props的组件不会更新渲染。
const initialState = { count: 1}function reducer(state = initialState, action){ switch(action.type){ case ADD_COUNT: state.count += 1; return { ...state }; //state改变,用到该state的组件不更新渲染 default: return state; }}
基于组件更新的原理,即比较新旧state或props是否指向同一块内存地址,如果是则不更新,如果不是则更新。也就是说就算是两个对象的值相等但不指向同一地址,dom也会重新渲染。这并不是我们想要看到的,我们需要的是当props的值改变的时候dom重新渲染。我们可以在shouldComponentUpdate()方法里面定义dom是否更新的条件,如 if ( props === nextProps ) return true。
react深复制
之前谈到的深复制基本是只能复制一层变量,或者必须嵌套着复制多层变量。如果想要更方便的完全复制一个对象,我们可以使用以下方法。
- immutable.js 库统一解决;
- lodash.jsclone(obj, true) 或cloneDeep(obj)方法
- 原生使用JSON.stringify()和parse()方法等