認識到的React生命週期分爲React16.0 之前的生命週期和React16.0之後的生命週期
React16.0 版本之前的生命週期
static defaultProps = {};
static propTypes = {};
constructor(props) {
super(props);
this.state = {};
}
componentWillMount() {}
render() {}
componentDidMount() {}
組件運行時
constructor(props) {
super(props);
// 常用於初始化狀態
console.log("1.組件構造函數執行");
}
componentWillMount() {
// 此時可以訪問狀態和屬性,可進行api調用等
console.log("2.組件將要掛載");
}
componentDidMount() {
// 組件已掛載,可進行狀態更新操作
console.log("3.組件已掛載");
}
componentWillReceiveProps(nextProps) {
// 父組件傳遞的屬性有變化,做相應響應
console.log("4.將要接收屬性傳遞");
}
shouldComponentUpdate(nextProps, nextState) {
// 組件是否需要更新,需要返回布爾值結果,優化點
console.log("5.組件是否需要更新?");
return true;
}
componentWillUpdate(nextProps, nextState) {
// 組件將要更新,可做更新統計
console.log("6.組件將要更新");
}
componentDidUpdate(prevProps, prevState) {
// 組件更新
console.log("7.組件已更新");
}
componentWillUnmount() {
// 組件將要卸載, 可做清理工作
console.log("8.組件將要卸載");
}
render() {
console.log("組件渲染");
return <div>生命週期探究</div>;
}
==
- 只有在 render 和 componentDidUpdate 中才能獲取到更新後的 this.state
- 在函數(componentWillReceiveProps)中調用 this.setState() 將不會引起第二次渲染
- 禁止在 shouldComponentUpdate 和 componentWillUpdate 中調用 setState,這會造成循環調用,直至耗光瀏覽器內存後崩潰。
組件的生命週期在不同狀態下的執行順序
-
當首次掛載組件時,按順序執行
getDefaultProps、getInitialState、componentWillMount、render 和
componentDidMount -
當卸載組件時,執行 componentWillUnmount 當重新掛載組件時,此時按順序執行
getInitialState、componentWillMount、render 和componentDidMount,但並不執行
getDefaultProps -
當再次渲染組件時,組件接受到更新狀態,此時按順序執componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate
當使用 ES6 classes 構建 React 組件時,static defaultProps = {} 其實就是調用內部的 getDefaultProps方法,constructor 中的 this.state = {} 其實就是調用內部的 getInitialState 方法
React16.4 的生命週期
- getDerivedStateFromProps
React v16.3 getDerivedStateFromProps無論是Mounting還是Updating,也無論是因爲什麼引起的Updating,全部都會被調用
React v16.4 static getDerivedStateFromProps(props, state)
在組件創建時和更新時的render方法之前調用,它應該返回 一個對象來更新狀態,或者返回null來不更新任何內容。
- getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 被調用於render之後,可以讀取但無法使用DOM的時候。
它使您的組件可以在可能更改之前從DOM捕獲一些信息(例如滾動位置)。此生命週期返回的任何值都將作爲參數傳遞給componentDidUpdate()。
官網示例
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) { //我們是否要添加新的 items 到列表?
// 捕捉滾動位置,以便我們可以稍後調整滾動.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) { //如果我們有snapshot值, 我們已經添加了 新的items.
// 調整滾動以至於這些新的items 不會將舊items推出視圖。
// (這邊的snapshot是 getSnapshotBeforeUpdate方法的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
constructor(props) {
super(props);
this.state = {
visible: false,
}
console.log('constructor')
}
static getDerivedStateFromProps(props, state) {
console.log('getDerivedStateFromProps', props, state);
return state
}
componentDidMount() {
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate', nextProps, nextState)
}
getSnapshotBeforeUpdate = (prevProps, prevState) => {
console.log('getSnapshotBeforeUpdate', prevProps, prevState);
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate', prevProps, prevState);
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
console.log('render');
return (
<div></div>
)
}
文章參考:
1、From TaobaoFED 【I like his website】高性能 React 組件
http://taobaofed.org/blog/2016/08/12/optimized-react-components/
2、什麼時候要在 React 組件中寫 shouldComponentUpdate
https://infoq.cn/article/2016/07/react-shouldComponentUpdate
3、【喜歡這篇文章講解的生命週期】 react如何通過shouldComponentUpdate來減少重複渲染
https://segmentfault.com/a/1190000016494335