简要介绍:React中的render存在着不必要的渲染,可以通过Puer Render(PureComponent)来减少渲染的次数,但是Puer Render只是进行浅比较,无法实现深层对象上的性能优化。Pure Render结合Immutable可以减少渲染次数。
1 . React中的render
仅通过React中的render,存在着不必要的渲染,这种不必要的渲染分为两大类。
(1)自身的state没有改变
在React的render中,只要发生setState行为,就会去重新渲染,即使setState的属性前后并没有发生变化,比如:
class TestComponent extends React.Component{
constructor(props){
super(props);
this.state={
count:0
}
}
componentDidMount(){
let self=this;
setTimeout(function(){
self.setState({
count:0
})
},1000)
}
componentDidUpdate(){
console.log('组件更新了');
}
render(){
return <div>1</div>
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
在这个组件中,我们setState的值在前后并没有发生改变,但是调用此组件会输出:
//组件更新了
- 1
说明只要setState发生了,即使值在前后没有发生变化,组件也会重新render。
(2)父组件传递的props会引起所有子组件render
父组件中的值传递给子组件,即使某些子组件中不需要重新渲染,也会重新render。举例来说,父组件为Father:
class Father extends React.Component{
constructor(props){
super(props);
this.state={
obj:{
title:'test immutable',
childZero:{
name:'childZero',
age:0
},
childOne:{
name:'childOne',
age:1
},
childTwo:{
name:'childTwo',
age:2
}
}
}
}
componentDidMount(){
let self=this;
let {obj}=this.state;
setTimeout(function(){
self.setState({
obj:obj
})
},1000)
}
render(){
const {obj}=this.state;
return <div>
<ChildZero obj={obj}/>
<ChildOne obj={obj}/>
<ChildTwo obj={obj}/>
</div>
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
父组件有3个子组件:
class ChildZero extends React.Component{
constructor(props){
super(props);
}
componentDidUpdate(){
console.log('childZero触发了更新')
}
render(){
return <div>3</div>
}
}
class ChildOne extends React.Component{
constructor(props){
super(props);
}
componentDidUpdate(){
console.log('childOne触发了更新')
}
render(){
return <div>3</div>
}
}
class ChildTwo extends React.Component{
constructor(props){
super(props);
}
componentDidUpdate(){
console.log('childTwo触发了更新')
}
render(){
return <div>3</div>
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
我们在父组件的componentDidMout方法中,setState然后观察子组件的更新情况,发现所有的子组件都会更新,具体输出为:
//childZero触发了更新
//childOne触发了更新
//childTwo触发了更新
- 1
- 2
- 3
2 . Pure Render可以减少浅层对象上不必要的更新
通过定义组件为Pure Render可以通过浅层比较,减少不必要的更新。我们通过使用PureComponent。同样的我们以1(1)中的为例:
class TestComponent extends React.PureComponent{
constructor(props){
super(props);
this.state={
count:0
}
}
componentDidMount(){
let self=this;
setTimeout(function(){
self.setState({
count:0
})
},1000)
}
componentDidUpdate(){
console.log('组件更新了');
}
render(){
return <div>1</div>
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
通过PureComponent来代替Component,此时如果仅仅是浅层对象属性,当setState前后属性不变时,那么就不会有不必要的渲染。但是对于深层对象而言,pure Render无法实现。
3 .通过Immutable实现深层对象的性能优化
Immutable实现了js中的不可变数据结构,immutable具有不可变性,持久性等特点,通过数据共享的方式,修改相应的属性实现深度克隆的过程只会影响父类属性。
通过immutablejs可以方便进行深层对象的“相等”判断。在React的性能优化中,在生命周期函数shouldComponetUpdate中判断在是否需要更新,进行前后props和前后state的深层比较。
shouldComponentUpdate(nextProps,nextState){
//进行深层判断使用immutable
const thisProps=this.props;
if(Object.keys(thisProps).length!==Object.keys(nextProps).length){
return true;
}
for(const key in nextProps){
console.log(is(thisProps[key],nextProps[key]));
if(!is(thisProps[key],nextProps[key])){
return true;
}
}
return false;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
如果返回true,那么会进行render,如果返回false,就不会render,从而可以控制深层对象是否需要重新render,实现了性能的优化。
这里使用immutable,主要是因为其拥有如下特点:
I)快,在深层对比对象(Map)或者数组(List)是否相同,比深层克隆式的比较快
II)安全,指的是对所有immutable的增删改查,都是增量,不会使得原始数据丢失
3.immutable的缺点
使用immutalbe也存在了一些缺点:
(1)immutablejs源文件较大
(2)具有很强的侵入性