React 之性能优化

包含父子组件的Tab切换

当我们将tab切换分离到子组件时很多人喜欢这样写

父组件:

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
class App extends Component{
constructor(props){
super(props);
this.state = {
};
this.type = 0;
}

tabSwitch(){
this.setState({
//change state
})
}

render(){
return (
<Tab renderFun={this.tabSwitch} type={this.type} />
)
}
}

ReactDOM.render(
<App />,
document.getElementById('root')
)

子组件:

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
export default class Tab extends Component{
constructor(props){
super(props);
this.state = {
tab:['tab1','tab2'],
current:this.props.type
};
}

tabSwitch(index){
this.setState({
current:index
},() => {
this.props.renderFun(this.state.current);
})
}

render(){
var _this = this;
return (
<div className='tab'>
{ this.state.tab.map(function(ele,index){
return <div key={index} className={'tab_' + index + ' ' + (_this.state.current == index ? 'tab_active':'')} onClick={_this.tabSwitch.bind(_this,index)}>{ele}</div>
})
}
</div>
)
}
}

这样的写法实现功能是没问题。当我们切换tab时,将点击的tab栏目传递给父组件,父组件改变state去重新渲染tab列表。但是这里虽然功能实现,但是写法上说不太react。

我们在子组件点击的时候,setState改变了current,子组件重新渲染,然后回调点击的tab给父组件,父组件执行setState会开始更新过程,这时候父组件的shouldComponentUpdate返回的肯定是true,
此时按照componentWillUpdate-》render-》componentDidUpdate,父组件完成了更新过程,由于父组件的渲染,所以子组件也开始更新过程,
此时由于newProps == this.props,所以子组件的shouldComponentUpdate返回false,更新过程终止。

比较正规的写法:

React建议将关系到渲染的数据保存在state中。这里能勾关系到渲染的就是这个type了。因为type的改变会导致我们的列表改变

父组件:

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
class App extends Component{
constructor(props){
super(props);
this.state = {
type:0
};
}

tabSwitch(index){
this.setState({
type:index
})
}

render(){
return (
<Tab renderFun={this.tabSwitch} type={this.state.type} />
)
}
}

ReactDOM.render(
<App />,
document.getElementById('root')
)

子组件:

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
export default class Tab extends Component{
constructor(props){
super(props);
this.state = {
tab:['tab1','tab2'],
};
this.current = this.props.type;
}

tabSwitch(index){
this.current = index;
this.props.renderFun(index);
}

render(){
var _this = this;
return (
<div className='tab'>
{ this.state.tab.map(function(ele,index){
return <div key={index} className={'tab_' + index + ' ' + (_this.current == index ? 'tab_active':'')} onClick={_this.tabSwitch.bind(_this,index)}>{ele}</div>
})
}
</div>
)
}
}
Do the best!