react生命週期和setState異步執行問題

什麼是生命週期?

生命週期是一個組件從建立到銷燬的過程。react會在不一樣的時間點注入相應的鉤子函數,以便於開發者進行更靈活的數據處理。react

生命週期只存在於類組件中,函數組件沒有生命週期。可是在後來的新版本react提供了hooks用於管理函數組件的狀態。

生命週期分三個階段

  1. 初始化階段;
  2. 更新階段;
  3. 銷燬階段。

初始化階段:

微信截圖_20200210201325.png

  1. constructor(props)函數:ajax

    • 只會執行一次,用於初始化數據;
    • 沒法使用setState,頁面還未掛載。
  2. componentWillMount函數:數組

    • 掛載數據以前執行,只會執行一次;
    • 可使用setState,可是很容易致使bug,不建議在這裏使用;
    • 新版的react已經移除該鉤子函數。
  3. render函數:性能優化

    • 每次渲染都會運行;
    • 將返回數據掛載在虛擬dom中,而後會構建真實的dom渲染頁面;
    • 不能調用setState方法,會形成無限遞歸內存泄露。
  4. componentDidMount函數:微信

    • 掛載完成階段,能夠在這裏開啓定時器,發送ajax請求業務數據等。

更新階段:屬性(props)發生變化或者狀態(state)發生變化

微信截圖_20200210201404.png

  1. componentWillReceiveProps(nextProps)函數:dom

    • 接受新的屬性值;
    • 使用該函數很容易致使一些bug,不建議使用。
    • 新版的react已經移除該鉤子函數。
  2. shouldComponentUpdate(nextProps, nextState)函數:異步

    • 必須返回一個布爾值,返回true執行render函數,返回false不執行render函數;
    • 用於減小沒必要要的渲染,作頁面性能優化。
  3. componentWillUpdate(nextProps, nextState)函數:函數

    • 組件即將被從新渲染;
    • 新版的react已經移除該鉤子函數。
  4. componentDidUpdate(prevProps, prevState, snapshot)函數:性能

    • 有時會在該函數中操做真實dom元素。

銷燬階段:

  1. componentWillUnmount()函數:優化

    • 只執行一次,在組件銷燬前執行;
    • 一般在該函數中作一些清理計時器,中斷請求的事情。

新版生命週期(16.3以上版本)

官方圖解已經畫的很清楚了,這裏不在贅述,主要說一下區別。

移除鉤子函數

  1. componentWillMount函數

    • 有一些bug難以解決,因此被移除。
  2. componentWillReceiveProps函數

    • 防止用戶濫用,致使數據來源混亂不可控,相似手錶定律一個頁面的值要麼來自屬性要麼來自狀態,必須是單一的,不然是一種反模式的寫法,容易形成bug。
  3. componentWillUpdate函數

    • 使用場景很少,因此被移除。

新增鉤子函數

  1. getDerivedStateFromProps(props, state)函數

    • 是一個靜態函數,使用是要加static關鍵字;
    • 在render以前調用;
    • 返回的值替換原來的state,返回null不改變state的值;
    • 多用於受控組件編寫。
  2. getSnapshotBeforeUpdate(prevProps, prevState)函數

    • 真實的dom發生改變,可是還沒渲染到頁面中,能夠進行一些dom操做;
    • 一般和componentDidUpdate(prevProps, prevState, snapshot)連用,返回的值做爲該函數的第三個參數傳入。

setState是異步的嗎?

  1. 可能是異步的,當setSate在dom事件處理函數中調用時就是異步的;
  2. 異步會致使當前的狀態更新不許確的問題。

舉個例子:

import React, {Component} from 'react'

export default class index extends Component{
    state = {
        count: 0
    }
    
    //點擊一次count加2
    hanldeClick = () => {
        this.State({
            count: this.state.count + 1
        })
        this.State({
            count: this.state.count + 1
        })
    }
    
    render(){
        return (
            <div onClick={this.hanldeClick}>{this.state.count}</div>
        )
    }
}

根據上述代碼,在點擊div以後,按道理,count的值應該變成2,但實際顯示的確是1

解決辦法:給setState傳入一個函數更新數據。

//點擊一次count加2
hanldeClick = () => {
    //使用這種方式獲取的上一個state是最新的
    this.State(function(state, props) {
        return {
            count: state.count + 2
        };
    })
}
爲何會形成這種現象?

react團隊以爲,dom事件處理函數中狀態處理會比較複雜,setState的次數比較多,若是每次setState就去更新頁面,會影響頁面渲染效率,因此會將事件中的多個setState合併成同一個。

相關文章
相關標籤/搜索