React.Component
和React.PureComponent
很相似,两则的区别在于,PureComponent
类帮我们以浅比较的方式对比props
和state
,实现了shouldComponentUpdate()
函数,在某些情况下,使用PureComponent
可以减少render
函数的执行,提升性能。
PureComponent能够提升性能
当Index组件继承Component
类
-
初次渲染时控制台会依次打印"
constructor
"、"render
"; -
当第一次点击按钮更新
state
时,控制台会依次打印"render
"、"componentDidUpdate
"; -
后续每次触发点击事件,尽管flag的值没有变化,控制台还是会依次打印"
render
"、"componentDidUpdate
",说明组件依然调用render()
、componentDidUpdate()
函数,显然这是多余的,通常我们会手动重新实现shouldComponentUpdate(nextProps, nextState)
函数判断state
、props
的状态再来决定是否需要重新渲染
import React from 'react';
class Index extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
flag:false
};
console.log('constructor');
}
changeState = () => {
this.setState({
flag: true
})
};
render() {
console.log('render');
return (
<div>
<button onClick={this.changeState}>Click me</button>
<div>
{this.state.flag.toString()}
</div>
</div>
);
}
componentDidUpdate() {
console.log("componentDidUpdate")
}
}
export default Index;
复制代码
当Index组件继承PureComponent
类
-
初次渲染和第一次点击按钮更新
state
时控制台输出同上面继承Component
一样没有变化 -
后续每次触发点击事件,控制台无输出, 省去执行
render
函数生成虚拟DOM,进行DIFF算法比较等后续操作
if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
}
复制代码
PureComponent
默认实现的shouldComponentUpdate()
方法使用的是浅比较: 即值的比较或引用的比较, 不会进行深层次的对比,所以当props
或state
的值是引用类型时,即使对象的值改变了,但是对象的引用没变
import React from 'react';
class IndexPage extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
arr: [1,2,3,4,5]
};
}
changeArr = () => {
let {arr} = this.state
arr.pop()
this.setState({
arr
})
console.log("changeArr", arr)
};
render() {
const { arr } = this.state
console.log('render', arr);
return (
<div>
<button onClick={this.changeArr}>pop</button>
<ul>
{
arr.map(item => <li key={item}>{item}</li>)
}
</ul>
</div>
);
}
componentDidUpdate() {
console.log("componentDidUpdate")
}
}
export default IndexPage;
复制代码
- 初次渲染时控制台会打印
render (5) [1, 2, 3, 4, 5]
- 当点击pop按钮时控制台会依次打印
changeArr (4) [1, 2, 3, 4]
,changeArr (4) [1, 2, 3]
......
但是render
函数不执行, 因为PureComponent
实现的shouldComponentUpdate()
认为值的引用没有变,故不执行后续的操作,只有在引用改变的情况下函数才会返回true
PureComponent也会影响子组件
下面例子中的render
函数只会在刚创建的时候执行一次, 后续的点击按钮操作,由于PureComponent
中的ShouldComponentUpdate()
执行浅比较(对象值的引用没变),不会触发render
函数的执行,其子组件也不会更新。
import React from 'react';
import Item from './Item'
class IndexPage extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
arr: [1,2,3,4,5]
};
}
changeArr = () => {
let {arr} = this.state
arr.pop()
this.setState({
arr
})
console.log("changeArr", arr)
};
render() {
const { arr } = this.state
console.log('render', arr);
return (
<div>
<button onClick={this.changeArr}>pop</button>
<ul>
<Item arr={arr} />
</ul>
</div>
);
}
componentDidUpdate() {
console.log("componentDidUpdate")
}
}
export default IndexPage;
复制代码
// Item.js
import React, { Fragment, Component } from 'react'
class Index extends Component {
render() {
const { arr } = this.props;
console.log("children", arr)
return (
<Fragment>
{
arr.map(item => <li key={item}>{item}</li>)
}
</Fragment>
)
}
}
export default Index;
复制代码
总结
PureComponent
已经用浅层对比props
、state
的方式替我们实现了shouldComponentUpdate()
, 不仅能影响自身,还会影响其子组件;PureComponent
某些情况下(props
或state
的值不经常变动, 因为浅比较也会耗时)可以提升性能;- 继承自
Component
中的组件shouldComponentUpdate()
默认情况下总是返回true;