React開發——step2 react16.3生命週期的更改和一些實踐注意

我總以爲react就像一個狀態機,它提供的生命週期讓我可以在某個特定時間作特定的事情,獲得我想要的結果。react

react16.3對生命週期的upgrade

React16打算廢棄的三個生命週期函數後端

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

官方說法是:官方計劃在17版本徹底刪除這三個函數,只保留UNSAVE_前綴的三個函數,目的是爲了向下兼容,可是對於開發者而言應該儘可能避免使用他們,而是使用新增的生命週期函數替代它們數組

取而代之的是兩個新的生命週期函數dom

  • static getDerivedStateFromProps
  • getSnapshotBeforeUpdate

生命週期概述

constructor
  1. 用於初始化內部狀態
  2. 惟一能夠直接修改state的地方(不須要setState)
getSnapshotBeforeUpdate
  1. 在頁面render以前調用
  2. 典型場景:在render以前,獲取上一次render的dom狀態
getDerivedStateFromProps
  1. 當state須要從props初始化時使用
  2. 每次render都會調用
  3. 典型場景: 表單控件從父組件獲取默認值
  4. 注意事項: 官方不推薦常常使用
componentDidMount
  1. UI渲染完成後調用
  2. 只執行一次
  3. 典型場景: 獲取外部數據
componentWillUnMount
  1. 組件被移除時調用
  2. 典型場景:資源釋放

詳談sholudComponentUpdate

shouldComponentUpdate(nextProps, nextState)

shouldComponentUpdate是pureComponent裏面實現的方法,它用於比較屬性的值有沒有發生改變,若是沒有的話就不render了。
也就是說
component: 能夠本身實現shouldComponentUpdate
pureComponent:已經幫咱們實現了,要注意是淺比較。ide

這裏因爲arr是一個引用數據類型,它的地址沒有發生改變,因此咱們的PureComponent是不會觸發render的。你能夠把PureComponent改爲component就會發現可以re-render.函數

import React, { PureComponent, Component } from 'react';

class IndexPage extends PureComponent {
  constructor() {
    super();
    this.state = {
      arr:['1']
    };
    console.log('constructor');
  }

  changeState = () => {
    let { arr } = this.state;
    arr.push('2');
    console.log(arr);
    this.setState({
      arr
    })
  };
  
  render() {
    // if the component was extended by the component, it will re-render each time you click
    // if the component was extended by the purecomponent, it won't re-render if the value didn't change
    // if the value is an array, the location of arr doesn't change means the value doesn't change
    console.log('render'); 
    return (
      <div>
        <button onClick={this.changeState}>點擊</button>
        <div>
          {this.state.arr.map((item) => {
            return item;
          })}
        </div>
      </div>
    );
  }
}

export default IndexPage

固然,咱們能夠比較輕鬆地解決這個問題,就是new一個數組來賦值。this

this.setState({
      arr: [...arr] // create a new array, so it would re-render
  })

我認爲比較好的方式是:父組件用PureComponent, 子組件用Component,保證子組件可以follow父組件的變化。spa

一點疑惑: 從後端獲取數據 componentWillMount vs componentDidMount

首先對比一下兩個生命週期獲取數據的區別:
componentWillMount獲取數據:code

componentWillMount:
1. 執行willMount函數,等待數據返回component

2. 執行render函數

3. 執行didMount函數

4. 數據返回, 執行render

componentDidMount:
1. 執行willMount函數

2. 執行render函數

3. 執行didMount函數, 等待數據返回

4. 數據返回, 執行render
看起來,咱們在componentWillMount裏面獲取數據是能夠更節約時間的。
關於爲何廢棄它, 官方說法是這樣的:

UNSAFE_componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering. Generally, we recommend using the constructor() instead for initializing state.

Avoid introducing any side-effects or subscriptions in this method. For those use cases, use componentDidMount() instead.

side-effects說的多是:

  1. 若是使用服務端渲染的話,willMount會在服務端和客戶端各自執行一次,這會致使請求兩次(接受不了~),而didMount只會在客戶端進行。
  2. 在Fiber以後, 因爲任務可中斷,willMount可能會被執行屢次。

節省一次render時間,我想若是咱們在render裏面判斷數據沒有ready返回null或者一個Loading圖片,也是能夠作到的。

相關文章
相關標籤/搜索