場(chǎng)景
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class A extends Component {
componentWillMount() {
console.log('A: componentWillMount');
}
render() {
console.log('A: render');
return (
<div>
<div>456</div>
<div>A{this.props.a}</div>
</div>
);
}
componentDidMount() {
console.log('A: componentDidMount');
}
componentWillReceiveProps() {
console.log('A: componentWillReceiveProps');
}
shouldComponentUpdate() {
console.log('A: shouldComponentUpdate');
return true;
}
componentWillUpdate() {
console.log('A: componentWillUpdate');
}
// render
componentDidUpdate() {
console.log('A: componentDidUpdate');
}
}
class Page extends Component {
state = {
a: 1
};
componentWillMount() {
console.log('Page: componentWillMount');
}
render() {
console.log('Page: render');
return (
<div>
<div>123</div>
<A a={this.state.a} />
</div>
);
}
componentDidMount() {
console.log('Page: componentDidMount');
setTimeout(() => {
console.warn('Page: setState');
this.setState({
a: 1
});
}, 2000);
}
componentWillReceiveProps() {
console.log('Page: componentWillReceiveProps');
}
shouldComponentUpdate() {
console.log('Page: shouldComponentUpdate');
return true;
}
componentWillUpdate() {
console.log('Page: componentWillUpdate');
}
// render
componentDidUpdate() {
console.log('Page: componentDidUpdate');
}
}
ReactDOM.render(
<Page />,
document.getElementById('app')
);
解答
1. 日志分析
(1)即使沒有改變state
悼瘾,也會(huì)調(diào)用shouldComponentUpdate
。
this.setState({a:2});
(改變了state
)和this.setState({a:1});
(沒有改變state
)日志結(jié)果一樣。
// 當(dāng)前組件和子組件shouldComponentUpdate都為true
Page: componentWillMount
Page: render
A: componentWillMount
A: render
A: componentDidMount
Page: componentDidMount
Page: setState
Page: shouldComponentUpdate ---- true
Page: componentWillUpdate
Page: render
A: componentWillReceiveProps
A: shouldComponentUpdate ---- true
A: componentWillUpdate
A: render
A: componentDidUpdate
Page: componentDidUpdate
(2)如果A
組件的shouldComponentUpdate
返回false
。
那么A
組件的componentWillUpdate
render
componentDidUpdate
就都不執(zhí)行了。
// 子組件shouldComponentUpdate為false
Page: componentWillMount
Page: render
A: componentWillMount
A: render
A: componentDidMount
Page: componentDidMount
Page: setState
Page: shouldComponentUpdate ---- true
Page: componentWillUpdate
Page: render
A: componentWillReceiveProps
A: shouldComponentUpdate ---- false
Page: componentDidUpdate
注:這一點(diǎn)只是在當(dāng)前React版本中生效
Currently, if shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate() will not be invoked. Note that in the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false
may still result in a re-rendering of the component.
—— React.Component: shouldComponentUpdate()
(3)如果組件Page
的shouldComponentUpdate
返回false
。
那么Page
組件的componentWillUpdate
render
componentDidUpdate
就都不執(zhí)行了税弃。
// 當(dāng)前組件的shouldComponentUpdate為false
Page: componentWillMount
Page: render
A: componentWillMount
A: render
A: componentDidMount
Page: componentDidMount
Page: setState
Page: shouldComponentUpdate ---- false
注意,A
組件的componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
也都不執(zhí)行了凑队。
因?yàn)樵蚬咏M件的componentWillReceiveProps
是在父組件render
后執(zhí)行的,子組件componentDidUpdate
后顽决,父組件才會(huì)componentDidUpdate
短条。
2. DOM更新
在調(diào)試工具中查看哪些DOM被重新渲染
(1)打開chrome開發(fā)者工具
(2)按Esc
,打開console
(3)點(diǎn)擊console左邊的按鈕才菠,勾選Rendering
(4)勾選Paint Flashing
我們發(fā)現(xiàn)茸时,即使render
函數(shù)被調(diào)用,DOM也不是全部更新赋访,而是根據(jù)diff算法來更新可都。
3. 結(jié)論
只要執(zhí)行this.setState
缓待,則當(dāng)前組件的shouldComponentUpdate
就會(huì)被調(diào)用。
如果當(dāng)前組件的shouldComponentUpdate
返回true
渠牲,
則子組件的componentWillReceiveProps
shouldComponentUpdate
將被調(diào)用旋炒,不論子組件的props
是否被改變。
如果當(dāng)前組件的shouldComponentUpdate
返回false
签杈,
則子組件的componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
都不被調(diào)用瘫镇。
如果子組件的shouldComponentUpdate
返回true
,則調(diào)用componentWillUpdate
render
答姥,然后通過diff算法更新DOM铣除,最后調(diào)用componentDidUpdate
。
如果子組件的shouldComponentUpdate
返回false
鹦付,則子組件的componentWillUpdate
render
componentDidUpdate
都不被調(diào)用尚粘。
參考
React.Component: The Component Lifecycle
Reconciliation: The Diffing Algorithm