一、为什么使用?
React15.3中新加了一个 PureComponent 类,取代其前身 PureRenderMixin。顾名思义, pure 是纯的意思,PureComponent 即纯组件,PureComponent 是优化 React 应用程序最重要的方法之一,使用PureComponent可以减少不必要的 render 操作的次数,从而提高性能,而且可以少写 shouldComponentUpdate 函数,节省代码。
二、原理
当组件更新时,如果组件的 props 和 state 都没发生改变,render 方法就不会触发,省去 Virtual DOM 的生成和比对过程,达到提升性能的目的。具体就是 React 自动帮我们做了一层浅比较:
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps)
|| !shallowEqual(inst.state, nextState);
}
而 shallowEqual 又做了什么呢?会比较 Object.keys(state | props) 的长度是否一致,每一个 key是否两者都有,并且是否是一个引用,也就是只比较了第一层的值,确实很浅,所以深层的嵌套数据是对比不出来的。
三、原则
PureComponent的组件在props或者state的属性值是对象的情况下,并不能阻止不必要的渲染,是因为自动加载的shouldComponentUpdate里面做的只是浅比较,所以想要用PureComponent的特性,应该遵守原则:
- 确保数据类型是值类型
- 如果是引用类型,不应当有深层次的数据变化(解构)
四、用法
使用方式很简单:
import React { PureComponent, Component } from 'react';
class Foo extends (PureComponent || Component) {
//...
}
一些要注意的地方:
- 易变数据不能使用一个引用
handleClick() {
let {items} = this.state
items.push('new-item')
this.setState({ items })
}
render() {
return (
<div>
<button onClick={this.handleClick} />
<ItemList items={this.state.items} />
</div>
)
}
由于ItemList是一个纯组件,这时候点击它是不会被渲染的,但是我们的确向this.state.items加入了新的值,但是它仍然指向同一个对象的引用。但是,通过移除可变对象就很容易改变这种情况,使之能够正确被渲染。
handleClick() {
this.setState(prevState => ({
words: prevState.items.concat(['new-item'])
}))
}
- 空对象或空数组
有时候后台返回的数据中,数组长度为0或者对象没有属性会直接给一个 null,这时候我们需要做一些容错
class App extends PureComponent {
state = {
items: [{ name: 'test1' }, null, { name: 'test3' }]
}
store = (id, value) => {
const { items } = this.state;
items[id] = assign({}, items[id], { name: value });
this.setState({ items: [].concat(items) });
}
render() {
return (< div>
< ul>
{this.state.items.map((i, k) =>
< Item store={this.store} key={k} id={k} data={i || {}} />)
}
< /ul>
< /div>)
}
}
当某一个子组件调用 store 函数改变了自己的那条属性,触发 render 操作,如果数据是 null 的话 data 属性每次都是一个 {},{} ==== {} 是 false 的,这样无端的让这几个子组件重新 render 了。最好设置一个 defaultValue 为 {},如下:
defaultValue = {}
< Item store={this.store} key={k} id={k} data={i || defaultValue} />
网友评论