blog
blog copied to clipboard
React优化:竭尽全力的减少render渲染
前言
玩过React的同学都知道,render()
方法除了第一次组件被实例化,其他情况绝大多数是state改变触发的。
而render方法的执行,所带来的负担就是重新对比Virtual DOM
(虚拟DOM树),也就是重新执行Diff
算法,然后把要修改的的DOM重新update。
而我们总是在开发过程中会产生非常多不必要的重新渲染
如何减少render
的触发,是提升项目性能的关键之一。
入手点
减少render的入口在哪?当然是要知道哪些情况会触发render啦~
根据个人了解,触发render有以下两种情况:
- 组件实例化
- state变化、props变化
那么我们从这两点入手
优化
Immutable 和 componentShouldUpdate
在《React和Immutable》中,提到了使用Immutable
配合React的componentShouldUpdate
生命周期函数来减少不必要的render,效果非常明显,这里就不说了,建议大家一定去看一下
除了使用 Immutable ,还有其他方法来避免render执行吗?
先看看正常开发中,使用setState的情况:
constructor(props) {
super(props);
this.state = {};
}
render() {
console.log('render');
return (
<div>
<input onChange={this.change} />
<button onClick={this.submit}>提交</button>
</div>
);
}
change = e => {
this.setState({
value: e.target.value
});
};
submit = () => {
console.log(this.state.value);
};
执行上面代码,然后在input里输入123,看看控制台上发生了什么:

对没错,执行了3次render,我们想象一下,用户在登录界面输入账号和密码时,render 会执行多少次啊啊啊 简直要命。
那有什么方法可以解决呢?
使用防抖来减少render
防抖函数应用在高频率操作时,能避免无意义的代码执行,从而提高性能。
constructor(props) {
super(props);
this.state = {
inputVal: ''
};
}
render() {
console.log('render');
return (
<div style={{ margin: 50 }}>
<input onChange={this.change} />
<button onClick={this.submit}>提交</button>
</div>
);
}
timer = null;
change = e => {
//获取inputVal
const inputVal = e.target.value;
//防抖处理
clearTimeout(this.timer);
this.timer = setTimeout(() => {
//set值
this.setState({
inputVal
});
}, 200);
};
submit = () => {
console.log(this.state.inputVal);
};
我们依然将inputVal挂在state上面,由于onChange事件可以频繁的触发setState,所以我们从这里下手,在onChange事件里使用防抖来避免频繁触发setState,从而避免多次render带来的性能消耗。
我们在文本框里输入值,然后看看控制台打印的结果:

Yes! 可以看到 我们输入 Hello,控制台只打印出了一次 render ,非常好!
在开发中可以将防抖函数放在工具函数中方便调用哟~
减少setState 使用私有属性
现在我们改变一种写法:不使用setState
而是换成私有属性this.inputVal
来代替:
constructor(props) {
super(props);
this.inputVal;
}
render() {
console.log('render');
return (
<div style={{ margin: 50 }}>
<input onChange={this.change} />
<button onClick={this.submit}>提交</button>
</div>
);
}
change = e => {
this.inputVal = e.target.value;
};
submit = () => {
console.log(this.inputVal);
};
我们仍然输入123,然后看看控制台:

哇塞~~ render一次都没执行,现在点击提交,打印结果是 123,这正是我们想要的。
缺点
聪明的同学能发现一个问题,其实这样的优化有一个缺点:不能使用双向绑定。
在开发中,真正使用双向绑定的表单元素,一般会有其他效果必须依赖该表单元素的数据,比如省市区级联,市区的变化必须依赖省的数据。
所以如果没有必要使用双向绑定的,请尽量避免使用。
总结
减少render的执行次数,可以使用:
- Immutable 配合 shouldComponentUpdate 具体请看这里
- 使用防抖函数来减少不必要的setState,从而减少render次数
- 使用私有属性来替代setState