前言 先说说 shouldComponentUpdate
提起React.PureComponent
,我们还要从一个生命周期函数 shouldComponentUpdate
说起,从函数名字我们就能看出来,这个函数是用来控制组件是否应该被更新的。
简单来说,这个生命周期函数返回一个布尔值,如果返回true,那么当props或state改变的时候进行更新;如果返回false,当props或state改变的时候不更新,默认返回true。(这里的更新不更新,其实说的是执不执行render
函数,如果不执行render函数,那自然该组件和其子组件都不会重新渲染啦)
重写shouldComponentUpdate
可以提升性能,它是在重新渲染过程开始前触发的。当你明确知道组件不需要更新的时候,在该生命周期内返回false
就行啦!
下面是一个重写shouldComponentUpdate的例子:
class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}
>
Count: {this.state.count}
</button>
);
}
}
React.Component 与 React.PureComponent
言归正传,接下来说我们今天要讨论的React.Component
与 React.PureComponent
。
通常情况下,我们会使用ES6的class
关键字来创建React组件:
class MyComponent extends React.Component {
// some codes here ...
}
但是,你也可以创建一个继承React.PureComponent的React组件,就像这样
class MyComponent extends React.PureComponent {
// some codes here
}
那么,问题来了,这两种方式有什么区别呢?
- 继承PureComponent时,不能再重写shouldComponentUpdate,否则会引发警告(报错截图就不贴了,怪麻烦的)
Warning: ListOfWords has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.
- 继承PureComponent时,进行的是浅比较,也就是说,如果是引用类型的数据,只会比较是不是同一个地址,而不会比较具体这个地址存的数据是否完全一致
class ListOfWords extends React.PureComponent {
render() {
return
}
}
class WordAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
words: ['marklar']
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// This section is bad style and causes a bug
const words = this.state.words;
words.push('marklar');
this.setState({words: words});
}
render() {
return (
);
}
}
上面代码中,无论你怎么点击按钮,*ListOfWords*渲染的结果始终没变化,原因就是*WordAdder*的word的引用地址始终是同一个。
3. 浅比较会忽略属性或状态突变的情况,其实也就是,数据引用指针没变而数据被改变的时候,也不新渲染组件。但其实很大程度上,我们是希望重新渲染的。所以,这就需要开发者自己保证避免数据突变。
如果想使`2`中的按钮被点击后可以正确渲染*ListOfWords*,也很简单,在*WordAdder*的*handleClick*内部,将 `const words = this.state.words;` 改为`const words = this.state.words.slice(0);` 就行啦~(这时的words是在原来state的基础上复制出来一个新数组,所以引用地址当然变啦)
---------
此处博客,只是简单做个记录,再者就是思绪整理,增加印象。有误之处,欢迎来喷。。