react的父子組件執行順序

執行順序

1.父類的ComponentWillMount
2.父類的render
3.子類1的ComponentWillMount
4.子類1的render
5.子類2的ComponentWillMount
6.子類2的render
7.子類1的ComponentDidMount
8.子類2的ComponentDidMount
9.父類的ComponentDidMountreact

組件掛載的過程:

初始化props,經過類的靜態屬性defaultProps或者getDefaultProps函數,初始化的props會與父組件指定的props合併,最後賦值給this.props
constructor(),或者getInitialState
componentWillMount(),此時dom還沒渲染,在這裏執行的setState不會致使重繪,執行無效果
render()
componentDidMount(),在這裏執行的setState會致使重繪(或稱爲二次渲染)
被動更新流程(父組件調用setState)es6

componentWillReceiveProps(),這時子組件的props仍然是舊的,能夠在這裏把新的props經過setState設置進state中,不會觸發二次渲染
shouldComponentUpdate(),這裏讀取到的state是以上更新後的state
componentWillUpdate(),不能在這裏執行setState,執行了無效果
render()
componentDidUpdate(),能夠在這裏進行異步的setState
主動更新流程(當前組件調用setState)dom

執行的函數相比上面的被動更新流程,少了一個componentWillReceiveProps方法,其他的都同樣。
卸載異步

componentWillUnmount(),用於清除定時器、事件綁定;React 官方不建議在 componentWillMount() 修改 state ,一般建議在 componentDidMount(), 若是須要設置 state 的初始狀態,能夠在 (es6:)constructor() 或者 (es5:)getInitialState() 中設置。函數

setState是一個異步操做,修改的state必能經過this.state.xxx來立刻讀取,但能夠在setState的第二個參數(回調函數)中讀取更新後的值。執行這個函數的時候,新狀態會被存放進隊列中,稍後才進行狀態合併,接着觸發shouldComponentUpdate和render,因此連續屢次的setState不會影響效率,只會觸發一次renderui

import React from 'react';
import ReactDOM from 'react-dom';
const buildClass = (name)=>{
    return class extends React.Component{
        constructor(props) {
            super(props);
            console.log( name + ' constructor');
        }
        componentWillMount() {
            console.log( name + ' componentWillMount');
        }
        componentDidMount() {
            console.log( name + ' componentDidMount');
        }
        componentWillUnmount() {
            console.log( name + ' componentWillUnmount');
        }
        componentWillReceiveProps(nextProps) {
            console.log( name + ' componentWillReceiveProps(nextProps)');
        }
        shouldComponentUpdate(nextProps, nextState) {
            console.log( name + ' shouldComponentUpdate(nextProps, nextState)');
            return true;
        }
        componentWillUpdate(nextProps, nextState) {
            console.log( name + ' componentWillUpdate(nextProps, nextState)');
        }
        componentDidUpdate(prevProps, prevState) {
            console.log( name + ' componetDidUpdate(prevProps, prevState)');
        }
    }
}
class Child extends buildClass('Child'){
    render(){
        console.log('Child render')
        return (
            <div>child</div>
        )
    }
}
class Parent extends buildClass('Parent'){
    render(){
        console.log('Parent render')
        return (
            <Child />
        )
    }
}
ReactDOM.render(
    <Parent />,
    document.getElementById('root')
}

執行結果this

Parent constructor
Parent componentWillMount
Parent render
Child constructor
Child componentWillMount
Child render
Child componentDidMount
Parent componentDidMount

總結:當執行render子組件的時候,纔會進入子組件的生命週期,子組件的週期結束後,再回到上級的週期。es5

更新組件的兩種方式

1.主動更新:組件經過setState修改本身的狀態。
修改子組件的代碼:code

class Child extends buildClass('Child'){
    render(){
        console.log('Child render')
        return (
            <button onClick={()=>{this.setState({data:123})}}>child</button>
        )
    }
}

執行結果component

Child shouldComponentUpdate(nextProps, nextState)
Child componentWillUpdate(nextProps, nextState)
Child render
Child componetDidUpdate(prevProps, prevState)

2.被動更新:父組件經過props把本身的state傳遞給子組件,父組件執行setState更新狀態
還原子組件的代碼,修改父組件代碼以下:

class Parent extends buildClass('Parent'){
    render(){
        console.log('Parent render')
        return (
            <div>
                <Child />
                <button onClick={()=>{this.setState({data:123})}}>Parent</button>
            </div>
        )
    }

執行結果

Parent shouldComponentUpdate(nextProps, nextState)
Parent componentWillUpdate(nextProps, nextState)
Parent render
Child componentWillReceiveProps(nextProps)
Child shouldComponentUpdate(nextProps, nextState)
Child componentWillUpdate(nextProps, nextState)
Child render
Child componetDidUpdate(prevProps, prevState)
Parent componetDidUpdate(prevProps, prevState)

總結 :無論父組件有沒有把數據傳遞給子組件,只要父組件setState,都會走一遍子組件的更新週期。並且子組件被動更新會比主動更新所執行的流程多出來一個
componentWillReceiveProps 方法。

若是在以上被動更新的基礎上,修改buildClass中的代碼,使 shouldComponentUpdate返回false,代碼以下:

shouldComponentUpdate(nextProps, nextState) {
    console.log( name + ' shouldComponentUpdate(nextProps, nextState)');
    return false;
}

點擊parent中的更新按鈕,僅僅輸出一句:
Parent shouldComponentUpdate(nextProps, nextState)

結論:只要組件在以上函數中返回false,則子組件不會進行更新re-render,全部更新流程都不執行了。

個人解決方案

父類ComponentDidMount發請求
render中判斷數據是否拿到
拿到以後再掛載子類組件
而且爲了保證若是當前組件被封成一個Component以後其餘人可以正常使用
所以根據無狀態組件的特色
在當前組件的外層封裝無狀態組件(用來根據數據是否獲取肯定組件的加載時機)
這時候直接在父類中引入這個無狀態組件
保證父類不會知道這個組件被延遲加載

其餘解決方案

父組件仍然在componentDidMount裏面發送請求子組件在componentWillReceiveProps中判斷數據是否存在存在的話就在子類的componentWillReceiveProps中發送請求

相關文章
相關標籤/搜索