函数式编程是指程序里面的函数和表达式都能像数学中的函数一样,给定了输入值,输出是确定的。比如
const a = 1;function addOne(num) {return num + 1;}const b = addOne(a);
变量b出现,虽然使用了变量a的值,但是没有修改a的值,此时 a 依然等于 1;
再看react中的代码,假如初始化了this.state = { count: 1 }
class ReactDemo extends React.Component {state = { count: 1 };componentDidMount() {this.setState({ ...state, count: 2 }); // { count: 2 }}}
这里我们使用了this.state,但是没有修改 this.state 的引用地址和原始引用中的count值,保证了数据的不可变性;
什么是Immutable
Immutable值具有以下特性:
- Immutable 是一旦创建,就不能被更改的数据;
- 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象,保证旧数据同时可用且不变;
Immutable 实现采用了持久化数据结构(Persistent Data Structure),为了避免深拷贝把所有节点都复制一遍带来的性能损耗,Immutable 使用了结构共享(Structural Sharing),即如果对象树结点发生变化,只修改这个结点和受它影响的父节点,其他结点进行共享。
使用 Immutable 带来的好处正如 React 官网所说:
简化复杂的功能
如果直接修改数据,那么就很难跟踪到数据的改变。跟踪数据的改变需要可变对象可以与改变之前的版本进行对比,这样整个对象树都需要被遍历一次
跟踪数据的改变
如果发现对象变成了一个新对象,那么我们就可以说对象发生改变了。
React 中的 Immutable Data
幼儿园小朋友都知道,shouldComponentUpdate 钩子函数默认返回true,即只要父组件更新,子组件一定更新。React v15.3新增加了一个PureComponent类,能够对props和state进行浅比较来减少render函数的执行次数,避免不必要的组件渲染,实现性能上的优化。
注:对于函数组件,可使用
React.memo(YourFunctionComponent)实现同样的性能优化
可是 PureComponent 是什么原理呢?
我们知道JS中的变量类型分为基本类型(number、string、boolean、undefined、null、symbol)和引用类型(object),基本类型的值保存在栈内存当中,引用类型的值保存在堆内存当中,栈内存中只保存指向堆内存的引用。而浅比较就是只对栈内存中的数据进行比较。实现一个简单的浅比较就好理解了
function isDifferent(prev, next) {const prevKeys = Object.keys(prev);const nextKeys = Object.keys(next);if(nextKeys.length !== prevKeys.length) {return true;}return !prevKeys.every(key => Object.is(prev[key], next[key]));}
可以发现,这个比较并没有递归全部数据,可是平衡性能的一个结果。
这样,PureComponent 可以简单写为:
class PrueComponent extends React.Component {shouldComponent(nextProps, nextState) {return isDifferent(this.props, nextProps) || isDifferent(this.state, nextState);}}
这里提供一个使用 PureComponent 时 setState 无法触发渲染的反例,来理解一下上述功能:
class App extends PureComponent {state = {items: [1, 2]}componentDidMount() {const { items } = this.state;items.pop();this.setState({ items });}render() {return this.state.items.map(num => <div>{num}</div>);}}
上边这个例子使用了 PureComponent,而且只改变了数组items里的值,而没改变 items 的引用地址,所以认为 items 没有发生变化,不会触发 render 函数,不会触发组件的渲染。所以 PureComponent 最好是搭配 Immutable.js 进行使用,来达到性能优化的目的。
