1. 程式人生 > 程式設計 >關於React中setState同步或非同步問題的理解

關於React中setState同步或非同步問題的理解

目錄
  • 1. setState同步?非同步?
  • 2. 表現為非同步
    • 1. React 合成事件
    • 2. 生命週期函式
  • 3. 表現為同步
    • 1. 原生事件
    • 2. setTimeout
  • 4. setState的第二個引數

    1. setState同步?非同步?

    在 React 的類式元件中,我們可以使用setState方法更新state狀態。但有些時候使用setState之後,得不到最新的資料。

    其實 React 中setState本身執行的過程和程式碼是同步的,只是因為 React 框架本身的效能優化機制而導致的。React 中合成事件和生命週期函式的呼叫順序在更新之前,導致在合成事件和生命週期函式中無法立刻得到更新後的值,形成了非同步的形式。

    假如在一個合成事件中,迴圈呼叫了setState方法n次,如果 React 沒有優化,當前元件就要被渲染n次,這對效能來說是很大的浪費。所以,React 為了效能原因,對呼叫多次swww.cppcns.cometState方法合併為一個來執行。當執行setState的時候,state中的資料並不會馬上更新。

    前面已經說到,在 React 的合成事件和生命週期函式中直接呼叫setState,會表現出非同步的形式。

    除此之外,如果越過 React 的效能優化機制,在原生事件、setTimeout中使用setState,就會表現出同步的形式。

    2. 表現為非同步

    1. React 合成事件

    在 React 中直接使用的事件,如onChange、onClick等,都是由 React 封裝後的事件,是合成事件,由 React 管理。那麼由於效能優化的機制,在合成事件中直接呼叫setState,將表現出非同步的形式。

    如下程式碼,在合成事件onClick中,直接將state中的count加1,並在此之後列印count的值,結果第一次點選按鈕時,會打印出0,而不是最新的1。

    state = { count: 0 };
    add = () => {
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count); // 0
    };
    render() {
        return (
            <>
                <div>當前計數:{this.state.count}</div>
                <button onClick={this.add}>add</button>
            </>
        );
    }

    2. 生命週期函式

    生命週期函式也是由 React 所管理,在生命週期函式中直接呼叫setState,也會表現出非同步的形式。

    如下程式碼,在生命週期componentDidMount函式中,將state中的count加1,並在此之後列印count的值,結果打印出0,而不是最新的1。

    state = { count: 0 };
    componentDidMount() {
        this.setState({ count: this.state.count + 1 });
        console.log(this.state.count); // 0
    }
    render() {
        return (
            <>
                <http://www.cppcns.com;div>當前計數:{this.state.count}</div>
                <button>add</button>
            </>
        );
    }

    3. 表現為同步

    1. 原生事件

    setState本身執行的過程是同步的,使用原生事件,繞過 React 的管理,將表現出同步的形式。

    如下程式碼,通過id獲取到 DOM 元素,用原生方法繫結點選事件。在點選事件中,將state中的count加1,並在此之後列印count的值,結果會列印最新的count值1。

    state = { count: 0 };
    componentDidMount() {
        const btn = document.getElementById('btn');
        btn.onclick = () => {
            this.setState({ count: this.state.count + 1 });
            console.log(this.state.count); // 1
        };
    }
    render() {
        return (
            <>
                <div>當前計數:{this.state.count}</div>
                <button id="btn">add</button>
            </>
        );
    }

    2. setTimeout

    如下程式碼,在生命週期componentDidMount函式中寫了一個定時器setTimeout,在setTimeout內部將state中的count加1,並在此之後列印count的值,結果會列印最新的count值1。

    setState雖然也是寫在生命週期componentDidMount函式中的,但並不是直接寫在componentDidMount裡,而是套了一層setTimeout。這樣,setState就表現出同步的形式。

    state = { count: 0 };
    componentDidMount() {
        setTimeout(() => {
            this.setState({ count: this.state.count + 1 });
            console.log(this.state.count); // 1
        },0);
    }
    render() {
        return (
            <>
                <div>當前計數:{this.state.count}<http://www.cppcns.com;/div>
                <button>add</button>
            </>
        );
    }

    4. setState的第二個引數

    無論setState的物件式寫法,還是函式式寫法,都有第二個引數,為可選的回撥函式,這個回撥函式在狀態更新完畢、介面也更新後(render呼叫後)才被呼叫。

    如下程式碼所示,setState雖然直接在componentDidMount中呼叫,但在setState的回撥函式中列印count的值,得到了最新的值1,因為回撥函式在狀態更新完畢後才被呼叫,當然能得到最新的count了。

    state = { count: 0 };
    componentDidMount() {
        this.setState({ count: this.state.count + 1 },() => {
            console.log(this.state.count); // 1
        });
    }
    render() {
        return (
            <>
                <div>當前計數:{this.state.count}</div>
                <button>add</buhttp://www.cppcns.comtton>
            </>
        );
    }
    

    到此這篇關於關於React中setState同步或非同步問題的理解的文章就介紹到這了,更多相關React中setState同步或非同步內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!