SET-STATE有个毛病
虽然说改变状态并且通知组件重新渲染,但是不改状态值,只要触发setState就会通知组件重现渲染,也就是 setState({})也会通知组件重新渲染
解决方案:
React.PureComponent 基于浅比较的方式,给每一个组件设置shouldComponentUpdate(如果自己设置了,以自己为主),在里面把状态和属性都在对比,如果两种基于前比较都没有发生任何的更改,则不再重新渲染组件
注意:
- PureComponent是基于浅比较,所以只要属性值是引用类型,但是地址不变也不会重新渲染
- PureComponent对forceUpdate 无效(forceUpdata根本不走shouldComponentUpdate)
- 不能乱用,只有那些状态和属性不经常的更新的组件我们用来做优化,
- 对于经常更新的,这样处理后也会浪费性能,因为每一个浅比较也是需要消耗时间的
import React from 'react';
class CountShow extends React.PureComponent {
render() {
return <div>{this.props.num}</div>
}
}
class Count extends React.Component {
state = {
num: 0,
arr: [12, 3]
}
render() {
// 1.基于value 向祖先元素的上下文设置内容
return <>
<h3>计数器{this.state.arr}</h3>
<CountShow num={this.state.num}></CountShow>
<button onClick={ev => {
this.setState({
num: this.state.num + 1, // 不会重新渲染
arr: [...this.state.arr,1] // 会重新渲染
})
}}>累加</button>
</>
}
shouldComponentUpdate(nextProps, nextState) {
return !shallowEqual(nextState, this.state) || !shallowEqual(nextProps, this.props)
}
}
export default Count
原理
/**
* shallowEqual:封装一个浅比较的方法
* 只比较对象的第一级
* 如果属性值是基本类型,只需比较值是否一样,还有是否有增加减少
* 如果是引用类型,需要比较地址
* */
function shallowEqual(obj1, obj2) {
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}
for (let key in obj1) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
class CountShow extends React.Component {
render() {
return <div>
{this.props.num}
</div>;
}
}
export default class Count extends React.Component {
state = {
num: 0,
x: 100,
arr: [10, 20]
};
render() {
console.log('OK');
return <>
<CountShow num={this.state.num} />
<button onClick={ev => {
this.state.arr.push(30);
this.setState({
arr: [...this.state.arr]
});
}}>累加</button>
</>;
}
shouldComponentUpdate(nextProps, nextState) {
return !shallowEqual(this.state, nextState) || !shallowEqual(this.props, nextProps);
}
}