React學習之旅Part8:通過例子和示意圖弄懂React的生命週期

一、概述

什麼是生命週期

每個組件的實例從創建到運行再到銷燬 在這個過程中的特定階段會觸發一系列的事件
這些事件就叫做組件的生命週期函數

React的組件生命週期函數

React組件的生命週期分爲三部分:創建 運行 銷燬

組件創建階段
(在組件的整個生命週期中只會被執行一次)

  • componentWillMount / 組件將要掛載
  • render / 渲染虛擬DOM元素
  • componentDidMount / 組件已經掛載

組件運行階段
(根據props屬性或state屬性的改變 有選擇性地執行0或多次
若屬性從創建開始從未改變 那就是0次
屬性改變了多少次 就執行多少次)

  • componentWillReceiveProps / 組件將要接收屬性
  • shouldComponentUpdate / 組件是否需要更新(判斷 返回true則渲染頁面 返回false則不渲染頁面 但數據依舊還是最新的)
  • componentWillUpdate / 組件將要更新
  • render / 渲染虛擬DOM元素
  • componentDidUpdate / 組件完成更新

組件銷燬階段
(在組件的整個生命週期中只會被執行一次)

  • componentWillUnmount / 組件將要解除掛載

二、從案例中看生命週期

========== 組件創建階段 ==========

componentWillMount()render()componentDidMount()

import React from 'react';

export default class Hello extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state={
            msg:"aaa"
        }
    }

    // ★【componentWillMount】在組件即將掛載到頁面之前執行 此時頁面尚未掛載到頁面中 虛擬DOM也尚未創建
    componentWillMount() // 相當於Vue的created生命週期
    {
        // 此時無法獲取到頁面上的任何元素
        console.log(document.getElementById("myh3")) // 輸出undefined

        console.log(this.props.initCount) // 1
        console.log(this.state.msg) // aaa
        this.testFunction();
    }

    // 在render的return執行之前 此時虛擬DOM尚未創建 頁面上是空的 無法獲取任何元素
    render()
    {
    	console.log(document.getElementById("myh3")) // 輸出undefined
    	
        return <div>
            <h1>Counter Component</h1>
            <input type="button" value="+1"/>
            <hr/>
            <h3 id="myh3">當前數值爲{this.props.initCount}</h3>
        </div>
        // 在render執行完畢後 內存中就有了虛擬DOM 但頁面上依舊是尚未顯示
    }

    // ★【componentDidMount】在組件掛載到頁面上之後執行 此時頁面上已經有可見的DOM元素了
    // 在該函數中可以放心地去操作頁面上的DOM元素了 且最早能操作DOM元素的生命週期就是這個
    // 當執行完畢該函數後 即進入了運行中的狀態 該函數是創建階段的最後一個函數
    componentDidMount() // 相當於Vue的mounted生命週期
    {
        console.log(document.getElementById("myh3")) // 能獲取到DOM 不再是undefined了
    }

    testFunction()
    {
        console.log("just test...")
    }
}

========== 組件運行階段 ==========

shouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate

在這裏以一個計數器作爲案例:

import React from 'react'
import ReactDOM from 'react-dom'

import Counter from "@/components/Counter"

ReactDOM.render(<div>
    <Counter initCount={1}></Counter>
</div>,document.getElementById("app"))

(爲節省篇幅 在此片段只專門列舉組件運行階段的生命週期函數)

import React from 'react';
import ReactPropTypes from "prop-types";// 提供常見的數據類型 用於類型校驗

export default class Counter extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state={
            count:props.initCount
        }
    }

    render()
    {
    	// 在組件運行階段時 調用render函數 頁面上的DOM元素還是舊的
        console.log(this.refs.h3 && this.refs.h3.innerHTML)

        return <div>
            <input type="button" value="增加" onClick={() => {this.increaseCount()}}/>
            <hr/>
            <h3 id="myh3" ref="h3">當前數值爲{this.state.count}</h3>
        </div>
    }

    increaseCount = () => {
        this.setState({
            count:this.state.count+1
        })
    }

    // ★【shouldComponentUpdate】判斷組件是否需要更新
    // 注:shouldComponentUpdate裏獲取的數值有遲滯性(慢半拍) 通過this獲取的數據會是前一次的
	// 可以在shouldComponentUpdate的入參中定義nextProps和nextState以獲取props和state裏的實時數據(入參的名稱可任意取)
    shouldComponentUpdate(nextProps,nextState)
    {
        // shouldComponentUpdate要求必須返回一個布爾值 作爲組件更新生命週期是否繼續執行的參考
        // 若返回【true】 則繼續執行後面的生命週期
        // 若返回【false】 則不執行後面的生命週期了 若點擊增加按鈕 state中的值依舊會增加 但是後面的render函數並不會被調用 因此虛擬DOM和頁面上的數據都是舊的
        return true;
    }

    // ★【componentWillUpdate】在組件將要更新時執行 將要更新的意思就是已經確定要更新 但是還沒有實際的更新操作
    // 在進入該生命週期函數的時候 內存中的虛擬DOM和頁面上的DOM元素都還是舊的
    componentWillUpdate()
    {
        // 此時頁面上的DOM節點還是舊的 尚未更新
        console.log(this.refs.h3.innerHTML) // 比如頁面上展示的數值爲3 那麼此時這裏打印的還是2
    }

	// ★【componentDidUpdate】在組件完成更新後執行 此時state中的數據和虛擬DOM和頁面上的DOM都已更新爲最新的了
    componentDidUpdate()
    {
        console.log(this.refs.h3.innerHTML)
    }
}

componentWillReceiveProps

這裏以一個父子組件作爲案例:

import React from 'react';

// 父組件
export default class Parent extends React.Component
{
    constructor(props)
    {
        super(props);

        this.state={
            msg:"Old Parent Msg"
        }
    }

    render()
    {
        return <div>
            <h1>Parent</h1>
            <input type="button" value="修改" onClick={() => {this.changeMsg()}}/>
            <hr/>
            <Son parentMsg={this.state.msg}></Son>
        </div>
    }

    changeMsg = () => {
        this.setState({
            msg:"New Parent Msg"
        })
    }
}

// 子組件
class Son extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state={}
    }

    render()
    {
        return <div>
            <h3>Son : {this.props.parentMsg}</h3>
        </div>
    }

    // ★【componentWillReceiveProps】在組件將要接收外界傳來的props時執行
    // 當組件第一次被渲染到頁面上的時候並不會觸發該生命週期函數
    // 只有 外界通過某些事件重新修改了傳入的props數據 纔會觸發該生命週期函數
    componentWillReceiveProps(nextProps)
    {
        // 通過this.props獲得的並不是最新的props數據 而是被觸發後上一次的舊值
        // 若要獲取最新的屬性值 則需要在入參中定義nextProps 然後通過nextProps獲取
        console.log("舊值:"+this.props.parentMsg+" - 新值:"+nextProps.parentMsg)
    }
}

(組件銷燬階段不太方便演示 在此就不演示了)

生命週期函數的入參列表:

  • Mounting創建:
    • constructor()
    • componentWillMount()
    • render()
    • componentDidMount()
  • Updating更新:
    • componentWillReceiveProps(nextProps) // 獲取最新props
    • shouldComponentUpdate(nextProps, nextState) // 獲取最新屬性
    • componentWillUpdate(nextProps, nextState) // 獲取最新屬性
    • render()
    • componentDidUpdate(prevProps, prevState) // 在全部更新完畢後 可以獲取舊的屬性(prev)
  • Unmounting銷燬:
    • componentWillUnmount()

三、從示意圖中看生命週期

(畫了張示意圖 希望能夠幫助理解)
在這裏插入圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章