React.Component(V16.8.6)

組件的生命週期

掛載html

當組件實例被建立並插入 DOM 中時,其生命週期調用順序以下:react

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

componentWillMount() 以後將廢棄緩存

更新異步

當組件的 props 或 state 發生變化時會觸發更新。組件更新的生命週期調用順序以下:函數

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

componentWillUpdate() 、 componentWillReceiveProps() 以後將被廢棄this

卸載線程

當組件從 DOM 中移除時會調用以下方法:code

  • componentWillUnmount()

錯誤處理component

當渲染過程,生命週期,或子組件的構造函數中拋出錯誤時,會調用以下方法:htm

  • static getDerivedStateFromError()
  • componentDidCatch()

組件還提供了一些額外的 API:

  • setState()
  • forceUpdate()

單獨介紹

getDerivedStateFromProps

這個生命週期函數是爲了替代 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(prevProps, prevState)

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

Error boundaries 是 React 組件,它會在其子組件樹中的任何位置捕獲 JavaScript 錯誤,並記錄這些錯誤,展現降級 UI 而不是崩潰的組件樹。Error boundaries 組件會捕獲在渲染期間,在生命週期方法以及其整個樹的構造函數中發生的錯誤。

若是 class 組件定義了生命週期方法 static getDerivedStateFromError()componentDidCatch() 中的任何一個(或二者),它就成爲了 Error boundaries。經過生命週期更新 state 可以讓組件捕獲樹中未處理的 JavaScript 錯誤並展現降級 UI。

僅使用 Error boundaries 組件來從意外異常中恢復的狀況;不要將它們用於流程控制。

static getDerivedStateFromError(error)

今生命週期會在後代組件拋出錯誤後被調用。 它將拋出的錯誤做爲參數,並返回一個值以更新 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(error, info)

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是異步的,全部有時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

相關文章
相關標籤/搜索