React組件生命周期小結

下面所寫的,只適合前端的React。(React也支持后端渲染,而且和前端有點小區別,不過我沒用過。)

相關函數

簡單地說,React Component通過其定義的幾個函數來控制組件在生命周期的各個階段的動作。

在ES6中,一個React組件是用一個class來表示的(具體可以參考官方文檔),如下:

// 定義一個TodoList的React組件,通過繼承React.Component來實現
class TodoList extends React.Component {
  ...
}

這幾個生命周期相關的函數有:

constructor(props, context)

構造函數,在創建組件的時候調用一次。

void componentWillMount()

在組件掛載之前調用一次。如果在這個函數里面調用setState,本次的render函數可以看到更新后的state,并且只渲染一次。

void componentDidMount()

在組件掛載之后調用一次。這個時候,子主鍵也都掛載好了,可以在這里使用refs。

void componentWillReceiveProps(nextProps)

props是父組件傳遞給子組件的。父組件發生render的時候子組件就會調用componentWillReceiveProps(不管props有沒有更新,也不管父子組件之間有沒有數據交換)。

bool shouldComponentUpdate(nextProps, nextState)

組件掛載之后,每次調用setState后都會調用shouldComponentUpdate判斷是否需要重新渲染組件。默認返回true,需要重新render。在比較復雜的應用里,有一些數據的改變并不影響界面展示,可以在這里做判斷,優化渲染效率。

void componentWillUpdate(nextProps, nextState)

shouldComponentUpdate返回true或者調用forceUpdate之后,componentWillUpdate會被調用。

void componentDidUpdate()

除了首次render之后調用componentDidMount,其它render結束之后都是調用componentDidUpdate。

componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以對應起來。區別在于,前者只有在掛載的時候會被調用;而后者在以后的每次更新渲染之后都會被調用。

ReactElement render()

render是一個React組件所必不可少的核心函數(上面的其它函數都不是必須的)。記住,不要在render里面修改state。

void componentWillUnmount()

組件被卸載的時候調用。一般在componentDidMount里面注冊的事件需要在這里刪除。

更新方式

在react中,觸發render的有4條路徑。

以下假設shouldComponentUpdate都是按照默認返回true的方式。

  1. 首次渲染Initial Render
  2. 調用this.setState (并不是一次setState會觸發一次render,React可能會合并操作,再一次性進行render)
  3. 父組件發生更新(一般就是props發生改變,但是就算props沒有改變或者父子組件之間沒有數據交換也會觸發render)
  4. 調用this.forceUpdate

下面是我對React組件四條更新路徑地總結:

React組件更新路徑.png

注意,如果在shouldComponentUpdate里面返回false可以提前退出更新路徑。

一個React組件生命周期的測試例子

代碼比較簡單,沒有邏輯,只是在每個相關函數里面alert一下。<h1>點擊鏈接來試試這個例子。</h1>
源碼:

class LifeCycle extends React.Component {
    constructor(props) {
        super(props);
        alert("Initial render");
        alert("constructor");
        this.state = {str: "hello"};
    }

    componentWillMount() {
        alert("componentWillMount");
    }

    componentDidMount() {
        alert("componentDidMount");
    }

    componentWillReceiveProps(nextProps) {
        alert("componentWillReceiveProps");
    }

    shouldComponentUpdate() {
        alert("shouldComponentUpdate");
        return true;        // 記得要返回true
    }

    componentWillUpdate() {
        alert("componentWillUpdate");
    }

    componentDidUpdate() {
        alert("componentDidUpdate");
    }

    componentWillUnmount() {
        alert("componentWillUnmount");
    }

    setTheState() {
        let s = "hello";
        if (this.state.str === s) {
            s = "HELLO";
        }
        this.setState({
            str: s
        });
    }

    forceItUpdate() {
        this.forceUpdate();
    }

    render() {
        alert("render");
        return(
            <div>
                <span>{"Props:"}<h2>{parseInt(this.props.num)}</h2></span>
                <br />
                <span>{"State:"}<h2>{this.state.str}</h2></span>
            </div>
        );
    }
}

class Container  extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            num: Math.random() * 100
        };
    }

    propsChange() {
        this.setState({
            num: Math.random() * 100
        });
    }

    setLifeCycleState() {
        this.refs.rLifeCycle.setTheState();
    }

    forceLifeCycleUpdate() {
        this.refs.rLifeCycle.forceItUpdate();
    }

    unmountLifeCycle() {
        // 這里卸載父組件也會導致卸載子組件
        React.unmountComponentAtNode(document.getElementById("container"));
    }

    parentForceUpdate() {
        this.forceUpdate();
    }

    render() {
        return (
            <div>
                <a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.propsChange.bind(this)}>propsChange</a>
                <a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.setLifeCycleState.bind(this)}>setState</a>
                <a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.forceLifeCycleUpdate.bind(this)}>forceUpdate</a>
                <a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.unmountLifeCycle.bind(this)}>unmount</a>
                <a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.parentForceUpdate.bind(this)}>parentForceUpdateWithoutChange</a>
                <LifeCycle ref="rLifeCycle" num={this.state.num}></LifeCycle>
            </div>
        );
    }
}

ReactDom.render(
    <Container></Container>,
    document.getElementById('container')
);

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容