react UNSAFE生命週期函數替換

react 生命週期函數變動

react v16.3 版本的發佈,生命週期函數的變更去掉了如下三個html

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

同時爲了彌補失去上面三個週期的不足又加了兩個react

  • static getDerivedStateFromProps
  • getSnapshotBeforeUpdate

過分方案是在以前項目中使用去掉的函數添加前綴 UNSAFE_, 官網提示能夠繼續使用至 React 17。但在項目中依然會有一些waring ,建議修改。如下是項目中一些替換策略,涉及也是比較全面,且有我深刻淺出一一闡述。數組

UNSAFE_componentWillMount 的替換

componentWillMount 函數中的場景有一下種:bash

  • class component中state 初始化數據狀態的設置
    • 官網建議使用 constructor() 來初始化 state。
  • 異步拉取數據
    • 能夠放在componentDidMount 函數中 引用官網原句在此方法中引入任何反作用或訂閱。如遇此種狀況,請改用 componentDidMount()
  • 定時器
    • 能夠在 componentDidMount 函數中
    • 另外一種方式是把定時器的抽離新的子組件(涉及業務邏輯的均可以放在子組件中)

UNSAFE_componentWillReceiveProps 的替換

componentWillReceiveProps 函數在初始的props不會渲染。會在組件接受到新的 props 時調用。通常用於父組件更新狀態時子組件的從新渲染。替換的場景以下:dom

  • 對比 this.prop和nextProps
  • 根據 nextProps更新state的操做 (見例子2)
    • 不影響dom界面的顯示
    • 影響dom界面的顯示
  • 根據 nextProps更新state,而且有調用this.props的操做(見例子1)

替換策略:異步

  • 若是您須要 執行反作用 (side effect)(例如,數據獲取或動畫)以響應 屬性 (props) 的更改,使用 componentDidUpdate 生命週期方法ide

  • 使用 componentWillReceiveProps, 在屬性 (props) 改變 時從新計算一些數據,請使用 memoization 輔助工具-官網有例子函數

  • 使用 componentWillReceiveProps , 在屬性 (props) 改變時 「重置」 一些 state (狀態),考慮使用一個 徹底控制組件 或 一個 帶 key 的徹底不受控 組件工具

  • 可使用 static getDerivedStateFromProps + componentDidUpdate vs getSnapshotBeforeUpdate + componentDidUpdate性能

以上3種狀況是官網推薦, 也是比較簡單的方式。static getDerivedStateFromProps 函數是官網也不推薦使用的函數,因此命名就比較長, 項目中對對此函數的替換在不拆分組件, 沒有使用hook的狀況下使用第3種策略進行的改寫。

static getDerivedStateFromProps(props, state)在調用 render 方法以前被調用,包括初始裝載(mount)和後續更新時。 它應該返回一個更新 state (狀態) 的對象,或者返回 null 以不更新任何 state (狀態)。

getSnapshotBeforeUpdate(prevProps, prevState) 在最近一次的渲染輸出被提交以前調用, 它返回的值將做爲第三個 snapshot 參數傳遞給 componentDidUpdate() 。 不然這個參數將是 undefined componentDidUpdate(prevProps, prevState, snapshot)此方法能夠調用 setState()來操做 DOM 。但請注意,必須包含在條件語句中 像上面的例子同樣,不然你會致使無限循環。 這也會致使額外的從新渲染, 雖然對用戶不可見,可是會影響組件的性能。

例子1更改前

UNSAFE_componentWillReceiveProps(nextProps) {
    const { models = [], itemId, shopId } = nextProps.sellerData;
    const { itemId: currentItemId } = this.props.sellerData;
    if (itemId !== currentItemId && models.length && models.length > 0) {
      this.setState(
        {
          matchShop: {},  // 初始化state
        },
         // callback 中調用 this.props 中父組件的方法
        () => {
          this.init(models);
          this.props.onGetMatchingTable({
            modelid: models[0].model_id,
            itemId,
            shopId
          });
        }
      );
    }
  }

複製代碼

例子1更改後

// getDerivedStateFromProps 接收最新的 Props 值 nextProps、上一個 state 值 prevState 兩個參數,返回返回一個對象來更新 state,或者返回 null 表示不須要更新 state。

 static getDerivedStateFromProps(nextProps, prevState) {
    const { models = [], itemId, shopId } = nextProps.sellerData;
    const { itemId: currentItemId } =
      (prevState && prevState.preSellerData) || '';

    if (
      currentItemId !== '' &&
      itemId !== currentItemId &&
      models.length &&
      models.length > 0
    ) {
      return {
        matchShop: {},
      };
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState) {
    const { itemId: currentItemId } = prevProps.sellerData;
    const { models = [], itemId, shopId } = this.props.sellerData;
    if (itemId !== currentItemId && models.length && models.length > 0) {
      // console.log('prevState---this.props', this.props, prevState, prevProps);
      this.init(models);
      this.props.onGetMatchingTable({
        modelid: models[0].model_id,
        itemId,
        shopId
      });
    }
  }


複製代碼

例子2 state狀態中iptUrl 是在子組件中,而且都多處能夠變動,父組件傳值props 用戶能夠輸入url,這種狀況下使用 getDerivedStateFromProps靜態方法就會觸發頁面更改進入死循環。使用getSnapshotBeforeUpdate + componentDidUpdate進行替換修改。

// 更改前註釋狀態
 
  // UNSAFE_componentWillReceiveProps(nextProps) {
  //   if (nextProps.url !== this.state.iptUrl) {
  //     this.setState({
  //       iptUrl: nextProps.url,
  //       errMsg: ''
  //     });
  //   }
  // }
  
  
  // 更改後 
  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.url !== this.props.url) {
      return this.props.url;
    }
    return null;
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      this.setState({ iptUrl: this.props.url, errMsg: '' });
    }
  }
複製代碼

使用 Effect Hook

在React 16.8 版本中可使用 Effect Hook, useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。在hook 中沒有生命週期的概念,更改數據的操做均可以稱爲反作用。Effect Hook 可讓你在函數組件中執行反作用操做。

參考

react

相關文章
相關標籤/搜索