翻譯自 React 16 Lifecycle Methods: How and When to Use Them,做者:Scott Domeshtml
參考 React.Componentreact
概述:最近在學習 react v16.8.4,發現組件的生命週期發生了一些變化,原有的一些方法被廢棄,因此看了官方API介紹,再結合上述文章,作個總結。ajax
publish:2019-03-27canvas
自從我寫了關於 React 組件生命週期的第一篇文章以來,相關的鉤子函數、API已經發生了重大變化。 一些生命週期方法已被棄用,並引入了一些新的方法。 因此是時候進行更新了!網絡
因爲此次生命週期 API 有點複雜,我將這些方法分爲四個部分:安裝(Mounting),更新(Updating),卸載(Unmounting)和錯誤(Error)。app
├── constructor()dom
├── static getDerivedStateFromProps異步
├── renderide
├── componentDidMount函數
若是您的組件是 Class Component,則調用的第一就是組件構造函數。 這不適用於 Functional Component。
相關構造函數多是以下形式
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
}
複製代碼
構造函數的參數爲 props,你能夠利用 super
來傳入。
在構造函數中,你能夠初始化 state、設定默認值。甚至你能夠依據 props 來建立 state。
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
counter: props.initialCounterValue,
};
}
}
複製代碼
注意,如今構造函數是可選的,若是您的 Babel 設置支持 class fields,就能夠像這樣初始化狀態:
class MyComponent extends Component {
state = {
counter: 0,
};
}
複製代碼
這種方法是被你們所提倡的。 你仍然能夠根據 props 建立 state:
class MyComponent extends Component {
state = {
counter: this.props.initialCounterValue,
};
}
複製代碼
可是,若是須要使用 ref ,就仍須要構造函數。
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
blocks: [],
};
// 在 constructor 中建立 ref
this.grid = React.createRef();
}
}
複製代碼
咱們須要構造函數來調用 createRef,以建立對 HTMLElement 元素的引用。還可使用構造函數進行函數綁定,這也是可選的
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
blocks: [],
};
// 1
this.handleChange.bind(this)
}
// 2 等同於 1
handleChange = () => {}
}
複製代碼
constructor總結: 構造函數的最常法:設置 state,建立 ref 和方法綁定。
掛載時,getDerivedStateFromProps 是渲染前調用的最後一個方法
通常使用 getDerivedStateFromProps 能夠根據初始道具使用它來設置狀態。
static getDerivedStateFromProps(props, state) {
return { blocks: createBlocks(props.numberOfBlocks) };
}
// log {blocks: Array(20)}
console.log(this.state);
複製代碼
上述代碼中依據 props.numberOfBlocks 來初始化指望的 state(函數return爲狀態)。
注意: 咱們能夠將此代碼放在 constructor 中,與之相 getDerivedStateFromProps的優勢是它更直觀 - 它僅用於設置狀態,而構造函數有多種用途。
總結: getDerivedStateFromProps 的最多見用例(在mount期間):根據初始props返回狀態對象。
完成全部渲染的工做。它返回實際組件的 JSX,使用React時,將花費大部分時間在這裏。
渲染的最多見用例:返回 JSX 組件。
在第一次渲染組件以後,觸發此方法。
若是須要加載數據,請在此處執行。 不要嘗試在 constructor 中加載數據或渲染,緣由,react-interview-questions.
因爲AJAX是異步的,因此沒法保證在組件掛載以前 AJAX 請求完成解析。 若是確實如此,那就意味着你要在未掛載的組件上嘗試 setState,這不只不起做用,並且 React 報錯。 在componentDidMount中執行 AJAX 將保證有一個要更新的組件。
componentDidMount 觸發時,組件已完成第一 render,因此能夠進行一些操做:
<canvas>
元素上進行繪製基本上,在這裏你能夠作全部依賴 DOM 的設置,並開始得到你須要的全部數據,例如
componentDidMount() {
// 利用 ref 訪問 dom 元素
this.bricks = initializeGrid(this.grid.current);
this.interval = setInterval(() => {
// ajax 獲取數據
this.addBlocks();
}, 2000);
}
}
複製代碼
總結: 調用 AJAX 以加載組件的數據。
├── static getDerivedStateFromProps
├── render
是的,再來一次。 如今,它更有用了。
若是您須要根據 props 來更新 state,能夠經過 return 新的狀態對象來完成該任務。
注,不建議依據 props 來處理 state,也就是說,只有逼不得已才使用該方法。 如下是一些例子:
即便有上述狀況,一般也有更好的方法。 可是 getDerivedStateFromProps 能夠狀況變得更壞。
總結: getDerivedStateFromProps 通常用於 props 不足以支撐業務時,利用它來更新 state。
shouldComponentUpdate
典型的 React 教條,當一個組件收到新的 State 或 Props時,它應該更新。
但咱們的組件有點困惑,它不肯定是否要進行更新。
shouldComponentUpdate 方法的第一個參數爲 nextProps,第二個參數爲 nextState。shouldComponentUpdate 返回一個布爾值,用於控制組件是否更新。
shouldComponentUpdate 賦予咱們一項能力,只有在你關心的 props 改變時組件會才更新。
總結: 能夠準確地控制組件從新渲染的時間,經常使用於優化 React,具體。
新添加的方法,觸發時刻在 render 以後,最新的渲染輸出提交給 DOM 以前。
調用渲染和最後顯示更改之間可能會有延遲, 若是你須要獲取 DOM 改變以前的一些信息時,能夠利用這個鉤子函數。
從渲染到提交這個過程是異步的,因此若是在 componentWillUpdate 訪問 DOM 信息,在 componentDidUpdate 使用時,該信息可能發生了修改,這一部分以官網的例子來講明
class ScrollingList extends React.Component {
listRef = React.createRef();
getSnapshotBeforeUpdate(prevProps, prevState) {
// 若是在列表中添加新項目
// 獲取列表的當前高度,以便咱們稍後調整滾動
if (prevProps.list.length < this.props.list.length) {
return this.listRef.current.scrollHeight;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 若是咱們 snapshot 的值不爲空,說明添加了新項目
// 調整滾動,以便這些新項目不會將舊項目推出可視區域
if (snapshot !== null) {
this.listRef.current.scrollTop +=
this.listRef.current.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
複製代碼
總結: 查看當前 DOM 的某些屬性,並將該值傳遞給componentDidUpdat。
全部的改變都已經提交給 DOM。
componentDidUpdate 包含三個參數,以前的 props、state,以及 getSnapshotBeforeUpdate 的返回值,具體如上述例子。
總結: 對已經改變的 Dom 做出相關響應。
組件快要結束了。
在組件註銷以前,它會詢問您是否有任何最後一刻的請求。
您能夠在此處取消任何傳出網絡請求,或刪除與該組件關聯的全部事件偵聽器。
基本上,清理任何事情都只涉及有問題的組件 - 當它消失時,它應該徹底消失。
總結: 清除事件監聽、定時器等,防止內存泄漏。
發生了一些異常。
它可以捕捉在他們的子組件樹中任意地方的 JavaScript 錯誤,記錄這些錯誤。當咱們要展現一個 error 頁面時,能夠利用它來完成。
static getDerivedStateFromError(error) {
return { hasError: true };
}
複製代碼
注意: 您必須返回更新的狀態對象。 不要將此方法用於任何反作用。 而是使用下面的 componentDidCatch。
總結: 依據錯誤信息來修改組件的 state,同時展現出 error 頁面。
與上面很是類似,由於它在子組件中發生錯誤時被觸發。
與 getDerivedStateFromError 區別在於不是爲了響應錯誤而更新狀態,能夠執行任何反作用,例如記錄錯誤。
componentDidCatch(error, info) {
sendErrorLog(error, info);
}
複製代碼
注意: componentDidCatch 僅會捕獲渲染/生命週期方法中的錯誤。 若是在單擊處理程序中引起錯誤,則不會捕獲它。
一般只在特殊的地方使用錯誤邊界組件的 componentDidCatch。 這些組件包裝子樹的惟一目的是捕獲和記錄錯誤。
class ErrorBoundary extends Component {
state = { errorMessage: null };
static getDerivedStateFromError(error) {
return { errorMessage: error.message };
}
componentDidCatch(error, info) {
console.log(error, info);
}
render() {
if (this.state.errorMessage) {
return <h1>Oops! {this.state.errorMessage}</h1>;
}
return this.props.children;
}
}
複製代碼
總結: 捕獲、打印出錯誤信息。
以上是React v16的生命週期鉤子所適用的場景和具體使用方法。