React生命週期

前言

若是將組件比做咱們圖中的🐜,吊繩比做🐜(組件)的壽命,吊繩左端表示🐜的出生(組件的建立),右端表示🐜的死亡(組件的銷燬)。🐜從生到死的過程會觸發吊牌上的鉤子函數執行,在React中咱們把組件從建立到銷燬的過程當中須要觸發的鉤子函數稱之爲生命週期函數react

React生命週期

舊版

初始化階段(Initalization)

  • setup props ande state(設置組件的初始化屬性和狀態)

初始化狀態對象

static defaultProps = {
    name:'計數器'  //初始化默認的屬性對象
}
複製代碼

初始化屬性對象

constructor(props){
    super(props);
    this.state = {
        number:0
    }
}
複製代碼

掛載階段(Mounting)

掛載:將虛擬DOM轉化爲真實DOM的過程ajax

componentWillMount

組件掛載以前,在渲染過程當中可能會執行屢次,不推薦使用瀏覽器

render

組件掛載架構

componentDidMount

組件掛載以後,永遠只會執行一次,推薦在此階段執行反作用,進行異步操做。好比發ajax請求,操做DOMapp

更新階段(Updation)

屬性更新(props變化)

componentWillReceiveProps

組件收到新的屬性對象時調用,首次渲染不會觸發異步

shouldComponentUpdate

詢問組件是否能夠更新函數

  • 參數:新的屬性對象
  • 返回:boolean
    • true容許更新繼續向下執行
    • false不容許更新,中止執行,不會調用以後的生命週期函數
componentWillUpdate

組件更新以前測試

render

根據新的屬性對象從新掛載(渲染)組件ui

componentDidUpdate

組件更新完成this

狀態更新(state變化)

shouldComponentUpdate

詢問組件是否能夠更新

  • 參數:新的狀態對象
  • 返回:boolean
    • true容許更新繼續向下執行
    • false不容許更新,中止執行,不會調用以後的生命週期函數
componentWillUpdate

組件更新以前

render

根據新的狀態對象從新掛載(渲染)組件

componentDilUpdtae

組件更新完成

卸載階段(Unmounting)

componentWillUnmount

組件卸載以前調用

放碼過來

有興趣的朋友能夠根據如下代碼進行測試

import React, { Component } from 'react';
/** * 父組件 */
class Counter extends Component {
  static defaultProps = { //初始化默認的屬性對象
    name:'計數器'
  }
  constructor(props) {
    super(props);
    this.state = { // 初始化默認的狀態對象
      number:0
    }
    console.log('1. 父constructor初始化 props and state');
  }
  componentWillMount() {
    console.log('2. 父componentWillMount組件將要掛載');
  }
  componentDidMount() {
    console.log('4. 父componentDidMount組件掛載完成');
  }
  shouldComponentUpdate() {
    console.log('5. 父componentShouldUpdate詢問組件是否能夠更新');
    return true;
  }
  componentWillUpdate() {
    console.log('6. 父componentWillUpdate組件將要更新');
  }
  componentDidUpdate() {
    console.log('7. 父componentDidUpdate組件更新完成');
  }
  render() {
    console.log('3. 父render渲染,也就是掛載');
    const style = {display:'block'}
    return (
      <div style={{border:'10px solid green',pending:'10px'}}> {this.props.name}:{this.state.number} <button onClick={this.add} style={style}>+</button> {this.state.number %3 !== 0 && <SubCounter number={this.state.number}/>} </div> ); } add = () => { this.setState({ number:this.state.number+1 }) } } /** * 子組件 */ class SubCounter extends Component { static defaultProps = { number:10 } componentWillReceiveProps() { console.log('1. 子componentWillReceiveProps屬性將要發生變化 '); } shouldComponentUpdate(nextProps, nextState) { console.log('2. 子componentShouldUpdate詢問組件是否能夠更新'); // 調用此方法的時候會把新的屬性對象和新的狀態對象傳遞過來 if (nextProps.number % 3 === 0) { return true; } return false; } componentWillUnmount() { console.log(' 3.子componentWillUnmount組件將要卸載 '); } render() { return ( <div style={{border:'10px solid red'}}> {this.props.number} </div> ); } } export default Counter; 複製代碼

新版

建立時

constructor

初始化屬性和狀態

getDerivedStateFromProps

根據屬性對象派生狀態對象

  • 靜態方法
  • 參數:新的屬性對象,舊的狀態對象
  • 用途:在沒有這個生命週期函數以前,咱們使用的數據來源多是屬性對象,也多是狀態對象,在咱們的上文中的放碼過來階段就有所體現,咱們能夠經過這個生命週期函數將屬性對象派生到狀態對象上,使咱們在代碼中只經過this.state.XXX來綁定咱們的數據。示例以下
import React, { Component } from 'react';
/** * 父 */
class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number:0
    }
  }
  render() {
    return (
      <div> <p>{this.state.number}</p> <button onClick={this.add}>+</button> <SubCounter number={this.state.number}/> </div> ); } add = () => { this.setState({ number:this.state.number+1 }) } } /** * 子 */ class SubCounter extends Component { constructor(props) { super(props); this.state = { number:0 } } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.number % 2 === 0) { return {number:nextProps.number*2} } else { return {number:nextProps.number*3} } } render() { console.log(this.state); return ( <div> <p>{this.state.number}</p> </div> ); } } export default Counter; 複製代碼

render

掛載(渲染)組件

componentDidMount

組件掛載(渲染)完成

更新時

getDerivedStateFromProps

根據屬性對象派生狀態對象

  • 靜態方法
  • 參數:新的屬性對象,舊的狀態對象

shouldComponentUpdate

詢問組件是否能夠更新

  • 參數:新的狀態對象
  • 返回:boolean
    • true容許更新繼續向下執行
    • false不容許更新,中止執行,不會調用以後的生命週期函數

render

根據新的狀態對象從新掛載(渲染)組件

getSnapshotbeforeUpdate

獲取更新前的快照

  • 舉例:在咱們的平常開發中你必定會遇到這個問題,異步加載資源,當瀏覽器處於非第一屏的時候而且所在屏以前的模塊並無加載出來,你確定不但願在所在屏以前的模塊加載出來以後瀏覽器顯示窗口仍然處於當前的高度,而是但願仍然處於咱們所瀏覽屏的高度,在沒有這個生命週期以前react處理這個問題是很棘手的。

未使用getSnapshotbeforeUpdate

import React, { Component } from 'react';
class GetSnapshotBeforeUpdate extends Component {
  constructor(props) {
    super(props);
    this.wrapper = React.createRef();
    this.state = {
      messages:['4','3','2','1','0']
    }
  }
  componentDidMount() {
    setInterval(() => {
      this.setState(() => {
        this.state.messages.unshift(this.state.messages.length);
      }, () => {
          this.setState({
            messages: this.state.messages
          })
      })
    },1000)
  }
  render() {
    let style = {
      height: '100px',
      width: '200px',
      border: '1px solid red',
      overflow:'auto'
    }
    return (
      <ul style={style} ref={this.wrapper}> { this.state.messages.map((message, index) => <li key={index}>{message}</li>) } </ul>
    );
  }
}
export default GetSnapshotBeforeUpdate;
複製代碼

使用getSnapshotbeforeUpdate

import React, { Component } from 'react';
class GetSnapshotBeforeUpdate extends Component {
  ...
  getSnapshotBeforeUpdate() {
    // 返回更新內容的高度
    return this.wrapper.current.scrollHeight;
  }
  // 組件更新完畢
  componentDidUpdate(prevProps,prevState,prevScrollHeight) {
    console.log(prevProps,prevState,prevScrollHeight);
    this.wrapper.current.scrollTop = this.wrapper.current.scrollTop +
    (this.wrapper.current.scrollHeight - prevScrollHeight);
  }
  ...
export default GetSnapshotBeforeUpdate;
複製代碼

componentDidUpdate

組件更新完成

卸載時

componentWillUnmount

組件卸載以前

總結

數據獲取爲何必定要在componentDidMount裏面調用

  • constructor
    • constructor()中獲取數據的話,若是時間太長,或者出錯,組件就渲染不出來,整個頁面都無法渲染了

  • componentWillMount()
    • 【1】若是使用SSR(服務端渲染),componentWillMount會執行2次,一次在服務端,一次在客戶端。而componentDidMount不會。

    • 【2】React16以後採用了Fiber架構,只有componentDidMount聲明周期函數是肯定被執行一次的,相似componentWillMount的生命週期鉤子都有可能執行屢次,因此不加以在這些生命週期中作有反作用的操做,好比請求數據之類

  • componentDidMount()
    • 【1】確保已經render過一次。提醒咱們正確地設置初始狀態,這樣就不會獲得致使錯誤的undefined狀態。

    • 【2】componentDidMount方法中的代碼,是在組件已經徹底掛載到網頁上纔會調用被執行,因此能夠保證數據的加載。此外,在這方法中調用setState方法,會觸發重渲染。因此,官方設計這個方法就是用來加載外部數據用的,或處理其餘的反作用代碼。

新舊比較(廢三增二)

  • 廢棄了
    • componentWillMount
    • componentWillReceiveProps
    • componentWillUpdate
  • 增長了
    • getDerivedStateFromProps
    • getSnapshotbeforeUpdate
相關文章
相關標籤/搜索