掛載html
當組件實例被建立並插入 DOM 中時,其生命週期調用順序以下:react
componentWillMount() 以後將廢棄緩存
更新異步
當組件的 props 或 state 發生變化時會觸發更新。組件更新的生命週期調用順序以下:函數
componentWillUpdate() 、 componentWillReceiveProps() 以後將被廢棄this
卸載線程
當組件從 DOM 中移除時會調用以下方法:code
錯誤處理component
當渲染過程,生命週期,或子組件的構造函數中拋出錯誤時,會調用以下方法:htm
組件還提供了一些額外的 API:
這個生命週期函數是爲了替代 componentWillReceiveProps 存在的,因此在你須要使用componentWillReceiveProps的時候,就能夠考慮使用getDerivedStateFromProps來進行替代了。
二者的參數是不相同的,而getDerivedStateFromProps是一個靜態函數
,也就是這個函數不能經過this訪問到class的屬性
,也並不推薦直接訪問屬性。
而是應該經過參數提供的nextProps以及prevState來進行判斷,根據新傳入的props來映射到state。
須要注意的是,若是props傳入的內容不須要影響到你的state,那麼就須要返回一個null,這個返回值是必須的,因此儘可能將其寫到函數的末尾。
static getDerivedStateFromProps(nextProps, prevState) { const {type} = nextProps; // 當傳入的type發生變化的時候,更新state if (type !== prevState.type) { return { type, }; } // 不然,對於state不進行任何操做 return null; }
若是你的組件內部既須要修改本身的type,又須要接收從外部修改的type。
static getDerivedStateFromProps(nextProps, prevState) { const {type} = nextProps; // type可能由props驅動,也可能由state驅動,這樣判斷會致使state驅動的type被回滾 if (type !== prevState.type) { return { type, }; } // 不然,對於state不進行任何操做 return null; }
在非必須的時候,摒棄這種寫法。type要麼由props驅動,要麼徹底由state驅動。
若是實在沒有辦法解耦,那麼就須要一個hack來輔助:綁定props到state上。
constructor(props) { super(props); this.state = { type: 0, props, } } static getDerivedStateFromProps(nextProps, prevState) { const {type, props} = nextProps; // 這段代碼可能看起來很是混亂,這個props能夠被當作緩存,僅用做判斷 if (type !== props.type) { return { type, props: { type, }, }; } // 不然,對於state不進行任何操做 return null; }
上面的代碼能夠保證在進行多數據源驅動的時候,狀態可以正確改變。固然,這樣的代碼不少狀況下是會影響到別人閱讀你的代碼的,對於維護形成了很是大的困難。
getSnapshotBeforeUpdate() 在最近一次渲染輸出(提交到 DOM 節點)以前調用。它使得組件能在發生更改以前從 DOM 中捕獲一些信息(例如,滾動位置)。今生命週期的任何返回值將做爲參數傳遞給 componentDidUpdate()。
此用法並不常見,但它可能出如今 UI 處理中,如須要以特殊方式處理滾動位置的聊天線程等。
應返回 snapshot 的值(或 null)。
class ScrollingList extends React.Component { constructor(props) { super(props); this.listRef = React.createRef(); } getSnapshotBeforeUpdate(prevProps, prevState) { // 咱們是否在 list 中添加新的 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> ); } }
在上述示例中,重點是從 getSnapshotBeforeUpdate 讀取 scrollHeight 屬性,由於 「render」 階段生命週期(如 render)和 「commit」 階段生命週期(如 getSnapshotBeforeUpdate 和 componentDidUpdate)之間可能存在延遲。
Error boundaries 是 React 組件,它會在其子組件樹中的任何位置捕獲 JavaScript 錯誤,並記錄這些錯誤,展現降級 UI 而不是崩潰的組件樹。Error boundaries 組件會捕獲在渲染期間,在生命週期方法以及其整個樹的構造函數中發生的錯誤。
若是 class 組件定義了生命週期方法 static getDerivedStateFromError() 或 componentDidCatch() 中的任何一個(或二者),它就成爲了 Error boundaries。經過生命週期更新 state 可以讓組件捕獲樹中未處理的 JavaScript 錯誤並展現降級 UI。
僅使用 Error boundaries 組件來從意外異常中恢復的狀況;不要將它們用於流程控制。
今生命週期會在後代組件拋出錯誤後被調用。 它將拋出的錯誤做爲參數,並返回一個值以更新 state
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染能夠顯降級 UI return { hasError: true }; } render() { if (this.state.hasError) { // 你能夠渲染任何自定義的降級 UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
注意:getDerivedStateFromError() 會在渲染階段調用,所以不容許出現反作用。 如遇此類狀況,請改用 componentDidCatch()。
componentDidCatch() 會在「提交」階段被調用,所以容許執行反作用。 它應該用於記錄錯誤之類的狀況:
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染能夠顯示降級 UI return { hasError: true }; } componentDidCatch(error, info) { // "組件堆棧" 例子: // in ComponentThatThrows (created by App) // in ErrorBoundary (created by App) // in div (created by App) // in App logComponentStackToMyService(info.componentStack); } render() { if (this.state.hasError) { // 你能夠渲染任何自定義的降級 UI return <h1>Something went wrong.</h1>; } return this.props.children; } }
由於setState是異步的,全部有時setState後獲取this.state數據並不許確,能夠以下操做:
state = { name:'initName' } this.setState((state,props)=>{ console.log(state,props); return {name:'name-change'}; }) const {name}=this.state; this.setState({name:'name-change'},()=>{ console.log(this.state.name,name) // name-change initName })
官方文檔:https://zh-hans.reactjs.org/docs/react-component.html#static-getderivedstatefromprops