iT邦幫忙

0

React Class Component 生命週期 - Update/Unmount 篇

挑戰 React 第二十二篇

上篇講到生命週期主要分成以下四大類:

  1. Mounting
  2. Updating
  3. Unmounting
  4. Error Handling

Update

Update 生命週期

Update 有五個生命週期

  1. static getDerivedStateFromProps(nextProps, prevState)
    承上篇自己沒用過這個方法,但官網表示:
    • 是一個 static 靜態函數,因此無法操作 class 中的屬性 (ex. this.state)
    • 無條件的根據 prop 更新內部 state,也就是只要有傳入prop 值, 就更新state
    • 只有 prop 和 state 不同時才更新 state
  2. shouldComponentUpdate(nextProps, nextState, nextContext)
    • React 的預設行為是每當 state 有所改變時就重新 render,而這個生命週期可以讓 component 是否要 rerender,但官方建議不要依賴這個方法來「避免」 render
    • 使用於效能最佳化
  3. render()
    • 回傳 React Element
  4. getSnapshotBeforeUpdate(prevProps, prevState)
    自己沒用過這個方法,但官網表示:
    • 會在最近一次 render 的 output 被提交給 DOM 時被呼叫
    • 這個生命週期方法回傳的值會被當作一個參數傳遞給 componentDidUpdate()
    • 它讓你在 DOM 改變之前先從其中抓取一些資訊(例如滾動軸的位置)
    • 回傳 null or snapshot的值
  5. componentDidUpdate(prevProps, prevState, snapshot)
    • call API
    • Rerender 的時候只會 call 一次

官方表示 getDerivedStateFromProps / shouldComponentUpdate / getSnapshotBeforeUpdate 這三個生命週期比較少使用。

實際範例

利用 console.log() 印出生命週期

ParentLifeCycle

import React, { Component } from 'react';
import ChildLifeCycle from './ChildLifeCycle';

class ParentLifeCycle extends Component {
  constructor(props) {
    super(props);
  
    this.state = {
       name: 'aaaa',
    }
    console.log('Parent Constructor');
  }
  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('Parent getDerivedStateFromProps');
    // 回傳 null 表示 state 無異動
    return null;
  }

  componentDidMount() {
    console.log('Parent componentDidMount');
  }

  shouldComponentUpdate(nextProps, nextState, nextContext) {
    console.log('Parent shouldComponentUpdate');
    // 預設值為 true
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('Parent getSnapshotBeforeUpdate');
    return null;
  }

  componentDidUpdate() {
    console.log('Parent componentDidUpdate');
  }

  render() {
    console.log('Parent render');
    return (
      <div>
        <div>Parent LifeCycle</div>
        <ChildLifeCycle />
      </div>
    )
  }
}

export default ParentLifeCycle;

ChildLifeCycle

import React, { Component } from 'react';

class ChildLifeCycle extends Component {
  constructor(props) {
    super(props);
  
    this.state = {
       test: 'aaaa',
    }
    console.log('Child Constructor');
  }
  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('Child getDerivedStateFromProps');
    // 回傳 null 表示 state 無異動
    return null;
  }

  componentDidMount() {
    console.log('Child componentDidMount');
  }

  shouldComponentUpdate(nextProps, nextState, nextContext) {
    console.log('Child shouldComponentUpdate');
    // 預設值為 true
    return true;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('Child getSnapshotBeforeUpdate');
    return null;
  }

  componentDidUpdate() {
    console.log('Child componentDidUpdate');
  }
  
  render() {
    console.log('Child render');
    return (
      <div>
        <div>Child LifeCycle</div>
      </div>
    )
  }
}

export default ChildLifeCycle;

下面截圖網頁呈現目前只有載入的生命週期

加入更新狀態的 click 事件

changeName = () => {
    this.setState({
      name: 'changeName'
    });
  }

  render() {
    console.log('Parent render');
    return (
      <div>
        <div>Parent LifeCycle</div>
        <button onClick={this.changeName}>update state</button>
        <ChildLifeCycle />
      </div>
    )
  }

再次查看按了change state 的 console.log

Unmounting

Unmounting 生命週期

只有一個 componentWillUnmount()

  • 在ㄧ個 component 被 unmount 和 destroy 後馬上被呼叫
  • 不應該在 componentWillUnmount() 內呼叫 setState()
  • 移除計時器(setInterval)和網路請求或是任何在 componentDidMount() 內建立的 subscription

參考 React 官方網站連結


尚未有邦友留言

立即登入留言