組件的生命周期(Life Cycle)包含三個階段:掛載(Mounting)、更新(Updating)和卸載(Unmounting),在每個階段都會有相應的回調方法(也叫鉤子)可供選擇,從而能更好的控制組件的行為。
## 一、掛載
  在這個階段,組件會完成它的首次渲染,先執行初始化,再被掛載到真實的DOM中,其中依次調用的方法有constructor()、componentWillMount()、render()和componentDidMount()。除了render(),其他三個方法都只會運行一次。
**1)constructor()**
  在生命周期中,類的構造函數constructor()會率先被執行,用于初始化組件的狀態、接收外部傳遞進來的數據、綁定成員方法的this指向等工作。
**2)componentWillMount()**
  componentWillMount()方法會運行在render()之前,它是渲染之前的回調函數。不過,由于在這個方法中執行的任務都能提前到constructor()中,因此實際項目中很少會用到它。
**3)render()**
  render()是在定義組件時必須聲明的方法,它是一個無副作用的純函數,可根據組件的props和state得到一個React元素、null或false等返回值,并且在render()方法中不能調用改變組件狀態的this.setState()方法。注意,將元素渲染到頁面DOM中的工作都由React負責,而不是render()方法。
**4)componentDidMount()**
  componentDidMount()方法會運行在render()之后,它是渲染之后的回調函數。此時組件已被掛載到頁面中,可以執行DOM相關的操作,例如異步讀取服務器中的數據并填充到組件中、調用jQuery代碼等。
  下面的組件沒有實際用途,僅僅是為了演示四個回調函數,其中componentWillMount()和componentDidMount()都成功調用了this.setState()方法。
~~~js
class Btn extends React.Component {
constructor(props) {
super(props);
this.state = {
name: props.name
};
}
componentWillMount() {
this.setState({age: 28});
}
render() {
return <button>{this.state.name}</button>;
}
componentDidMount() {
$.post("server.php", {id:1}, json => {
this.setState({age: json.data.age});
}, "json");
}
}
~~~
## 二、更新
  引起組件更新(即重新渲染)的方式有三種,第一種是由父組件向下傳遞props(即調用父組件的render()方法)引起的更新,依次會調用五個方法:componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate()、render()和componentDidUpdate()。第二種是通過改變自身state(即調用this.setState()方法)引起的更新,會忽略componentWillReceiveProps()方法,只執行四個回調函數。第三種是通過組件的forceUpdate()方法強制更新,只有后三個回調函數會被執行。在下面的組件中,定義了更新階段的五個回調函數,并且點擊按鈕就會觸發強制更新。
~~~js
class Btn extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "strick"
};
}
dot() {
this.setState({name: "freedom"});
this.forceUpdate(); //強制更新
}
componentWillReceiveProps(nextProps) { }
shouldComponentUpdate(nextProps, nextState) { return true; }
componentWillUpdate(nextProps, nextState) { }
render() {
return <button onClick={this.dot.bind(this)}>{this.state.name}</button>;
}
componentDidUpdate(prevProps, prevState) { }
}
~~~
**1)componentWillReceiveProps()**
  componentWillReceiveProps()方法常用于執行props更新后的邏輯,只有第一種更新方式才會調用它,該方法能接收一個名為nextProps的參數,表示父組件傳遞進來的新的props。當需要通過this.setState()方法將nextProps中的數據同步到內部狀態時,要先比較nextProps和this.props中的值是否相同,再決定是否執行同步。由于在componentWillReceiveProps()中能調用this.setState()方法,因此為了避免進入一個死循環,在調用this.setState()方法更新組件時就不會觸發它。
**2)shouldComponentUpdate()**
  shouldComponentUpdate()用于決定是否繼續組件的更新,它能接收2個參數:nextProps和nextState,分別表示新的props和state,通過比較nextProps、nextState和組件當前的this.props、this.state能得出一個布爾類型的返回結果。當返回結果為false時,組件會停止更新,后續的componentWillUpdate()、render()和componentDidUpdate()也不會被執行。將這個方法使用恰當的話,能減少冗余的渲染,優化組件的性能。
**3)componentWillUpdate()和componentDidUpdate()**
  componentWillUpdate()和componentDidUpdate()分別運行在render()之前和之后,它們都能接收2個參數,前者提供更新后的props和state,后者提供更新前的props和state。在componentWillUpdate()中,不能調用this.setState()方法,以免發生不必要的死循環。
## 三、卸載
  當組件在從DOM中被卸載之前,會觸發一個無參數的componentWillUnmount()方法。在該方法內適合做些清理的工作,例如清除定時器、移除多余的DOM元素等。下面演示了處理卸載的過程,限于篇幅省略了組件的構造函數和render()方法,只給出了關鍵代碼。
~~~js
class Btn extends React.Component {
componentWillUnmount() {
clearInterval(timeout);
}
}
var container = document.getElementById("container");
ReactDOM.render(<Btn>提交</Btn>, container);
ReactDOM.unmountComponentAtNode(container); //移除DOM中的組件
~~~
## 四、流程圖
  接下來用一張總的流程圖(如圖5所示)來說明生命周期各個方法之間的關系,灰底的方法表示在其內部能調用this.setState()方法。
:-: 
圖5 組件生命周期流程圖
## 五、過時和新增的回調方法
**1)過時**
  從React v16.3開始,有3個生命周期方法被標記為過時:componentWillMount()、componentWillReceiveProps()和componentWillUpdate(),目前它們仍然有效,但不建議在新代碼中使用,官方為它們新增了一個以“UNSAFE\_”作為前綴的別名。
**2)新增**
  React v16新增了兩個生命周期方法,如下所列。
  (1)static getDerivedStateFromProps(nextProps, prevState)
  靜態方法getDerivedStateFromProps()用來替代componentWillReceiveProps()。它在render()方法之前觸發,包含兩個參數:nextProps和prevState,分別表示新的props和舊的state。如果返回一個對象,那么更新state;如果返回null,那么就不更新state。
  (2)getSnapshotBeforeUpdate(prevProps, prevState)
  getSnapshotBeforeUpdate()方法用來替代componentWillUpdate()。它在最近一次渲染輸出(即更新DOM)之前觸發,包含兩個參數:prevProps和prevState,分別表示舊的props和舊的state,返回值會成為componentDidUpdate()的第三個參數。
*****
> 原文出處:
[博客園-React躬行記](https://www.cnblogs.com/strick/category/1455720.html)
[知乎專欄-React躬行記](https://zhuanlan.zhihu.com/pwreact)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020