細說React生命周期


新舊版本生命周期圖對比

16.3之前的版本

16.3之后的版本

react自16.x之后,添加了getDerivedStateFromProps, getSnapshotBeforeUpdate,如圖

生命周期的幾個階段

生命周期有幾個時期,分別為掛載,更新,卸載,我們看上方16.3之后版本的圖可以得出,其實每個時期還分為幾個階段:

  • render階段: 是指從到render函數執行完返回jsx結構之前的過程,這個過程的都是不包含副作用的純函數,這個過程包含的函數有
    • constructor
    • getDerivedStateFromProps
    • shouldUpdateComponent
    • render
    • getDerivedStateFromError
  • pre-commit階段: 是指從返回一個jsx結構到更新dom之前的過程,這個過程只有函數getSnapshotBeforeUpdate
  • commit階段: 是指更新dom,以及更新成功之后的過程,有函數
    • componentDidMount
    • componentDidUpdate
    • componentDidCatch

從上圖中看函數componentWillUnmount是在commit階段但是,我理解這個函數應該是在dom更新之前執行,我認為應該在pre-commit

掛載

所謂掛載其實就是組件第一次在dom樹種渲染的過程,在這個過程中會一次執行一些生命周期函數

constructor

構造函數用於初始化props,state以及綁定this指向,如果不需要這些操作可以省略構造函數,需要注意的是

  • 構造函數中不能調用setState, 而應該直接給state賦值
  • props是由外部傳進來的,所以不能修改props
  • 不能直將props中的值賦值給state,像這樣
constructor(props) {
 super(props);
 // 不要這樣做
 this.state = { color: props.color };
}

參考react官網介紹

conpomentWillMount(v17將移除)

這個方法會在render之前執行,這個方法也是在服務端渲染中唯一會調用的方法

getDerivedStateFromProps(v16.3加入)

conpomentWillMount 移除了取而代之的就是這個方法,這是一個靜態方法,實例無權訪問,在組件實例化之后,以及每次render之前調用。getDerivedStateFromProps的存在只有一個目的就是讓props更新的時候更新state,在這一點上跟componentWillReceiveProps是一致的,這兩個生命周期函數並不是只有在props更新的時候才會調用,而是當父組件重新渲染后,兩個生命周期函數都會調用

static getDerivedStateFromProps(props, state)

render

組件的render函數並不會像dom中插入元素,實際上render只是返回jsx結構,或者是數組,字符串等數據,最終由ReactDOM.render渲染到dom中,在自定義的類組件中,render函數必須實現,並且render應該為一個根據state和props來返回結果,不造成副作用的純函數

componentDidMount

在組件被掛載(插入到dom節點)后,立刻執行這個函數,可以在這個函數中請求數據,以及添加訂閱,但是要記得在函數componentWillUnmount中去取消訂閱

更新

當組件的props更新時,或者state更新時也會觸發一些生命周期函數來更新dom

props更新 componentWillReceiveProps(v17將移除)

當父組件的render被調用時,無論傳進來的props是否更新,這個函數都會調用,需要注意的是,在函數調用時,應該將參數與props做一個對比,判斷是否要更新state

  componentWillReceiveProps(nextProps) {
    // 只要 props.email 改變,就改變 state
    if (nextProps.email !== this.props.email) {
      this.setState({
        email: nextProps.email
      });
    }
  }

這個方法state更新時不會執行,v17之后由getDerivedStateFromProps取代

shouldComponentUpdate

這個函數返回一個布爾值,返回true的時候接下來會執行組件的render方法,默認情況下都是返回true的,如果為false則不會執行后續渲染,這個方法在掛載階段或者執行forceUpdate時不會執行。

shouldComponentUpdate(nextProps, nextState)

函數接受的參數為新的props和新的state所以在函數內部可以拿新的props和state與組件當前的props、state做一個對比,如果發現沒有變化則返回false。React官方建議使用React.PureComponent實現組件,這個組件的shouldComponentUpdate方法會對props和state分別做淺層對比,以此來提高性能,同時不建議在shouldComponentUpdate中去實現深層次的數據對比,以免影響效率

componentWillUpdate(v17將移除)

shouldComponentUpdate返回true,則會執行componentWillUpdate,在這個方法中,不能執行setState等其它會更新組件的方法(比如dispatch),可以在此方法中讀取 DOM 信息(例如,為了保存滾動位置),而在之后可以放到getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(v16.3引入)

getSnapshotBeforeUpdate(prevProps, prevState)

在render之后,dom更新之前回執行這個函數,一般會在此時讀取dom更新之前的一些信息(比如滾動條位置),此函數的所有返回值,都將作為參數傳給componentDidUpdate

componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot)

這里第三個參數就為上文中getSnapshotBeforeUpdate的返回值,componentDidUpdate會在dom加載完之后執行,在這個函數中就可以進行dom操作了

卸載

componentWillUnmount

組件銷毀之前調用,在這里更新state不會更新組件

錯誤處理

react在v16引入了錯誤邊界的概念,當子組件發生,當子組件的構造函數,生命周期以及子組件的構造函數出出錯的時候,會執行錯誤處理回調

getDerivedStateFromError

static getDerivedStateFromError(error)

當子組件拋出錯誤會觸發這個函數,錯誤信息為函數的參數,次函數可以返回一個新的值來更新state,組件可以根據更新的state實現一個降級UI,此方法在“render階段”執行,應該為一個純函數

componentDidCatch

componentDidCatch(error, info)

同樣當子組件拋出錯誤的時候回觸發,第二個參數為info,其中包含了組件調用棧的信息

console.log(info.componentStack);

這個函數是在“commit階段”執行的,所以可以在函數中調用setState來更新state

為什么react要在v17移除部分構造函數?

官方團隊認為,之前的幾個will生命周期函數會讓用戶產生很多誤解,在實際的使用場景中,也有很多錯誤的使用情況出現。所以直接替換為一個靜態方法getDerivedStateFromProps,這樣用戶就不能再這些方法內訪問到當前的實例了,從而也就不能調用setState,或者訪問refs了,減少了很多錯誤操作
其他原因可以參考鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM