基于PureComponent进行性能优化

175 阅读2分钟

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);
	}
}