關(guān)于React中setState同步或異步問題的理解
1. setState同步?異步?
在 React 的類式組件中,我們可以使用setState方法更新state狀態(tài)。但有些時(shí)候使用setState之后,得不到最新的數(shù)據(jù)。
其實(shí) React 中setState本身執(zhí)行的過程和代碼是同步的,只是因?yàn)?React 框架本身的性能優(yōu)化機(jī)制而導(dǎo)致的。React 中合成事件和生命周期函數(shù)的調(diào)用順序在更新之前,導(dǎo)致在合成事件和生命周期函數(shù)中無法立刻得到更新后的值,形成了異步的形式。
假如在一個(gè)合成事件中,循環(huán)調(diào)用了setState方法n次,如果 React 沒有優(yōu)化,當(dāng)前組件就要被渲染n次,這對性能來說是很大的浪費(fèi)。所以,React 為了性能原因,對調(diào)用多次setState方法合并為一個(gè)來執(zhí)行。當(dāng)執(zhí)行setState的時(shí)候,state中的數(shù)據(jù)并不會(huì)馬上更新。
前面已經(jīng)說到,在 React 的合成事件和生命周期函數(shù)中直接調(diào)用setState,會(huì)表現(xiàn)出異步的形式。
除此之外,如果越過 React 的性能優(yōu)化機(jī)制,在原生事件、setTimeout中使用setState,就會(huì)表現(xiàn)出同步的形式。
2. 表現(xiàn)為異步
1. React 合成事件
在 React 中直接使用的事件,如onChange、onClick等,都是由 React 封裝后的事件,是合成事件,由 React 管理。那么由于性能優(yōu)化的機(jī)制,在合成事件中直接調(diào)用setState,將表現(xiàn)出異步的形式。
如下代碼,在合成事件onClick中,直接將state中的count加1,并在此之后打印count的值,結(jié)果第一次點(diǎn)擊按鈕時(shí),會(huì)打印出0,而不是最新的1。
state = { count: 0 };
add = () => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 0
};
render() {
return (
<>
<div>當(dāng)前計(jì)數(shù):{this.state.count}</div>
<button onClick={this.add}>add</button>
</>
);
}
2. 生命周期函數(shù)
生命周期函數(shù)也是由 React 所管理,在生命周期函數(shù)中直接調(diào)用setState,也會(huì)表現(xiàn)出異步的形式。
如下代碼,在生命周期componentDidMount函數(shù)中,將state中的count加1,并在此之后打印count的值,結(jié)果打印出0,而不是最新的1。
state = { count: 0 };
componentDidMount() {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 0
}
render() {
return (
<>
<div>當(dāng)前計(jì)數(shù):{this.state.count}</div>
<button>add</button>
</>
);
}
3. 表現(xiàn)為同步
1. 原生事件
setState本身執(zhí)行的過程是同步的,使用原生事件,繞過 React 的管理,將表現(xiàn)出同步的形式。
如下代碼,通過id獲取到 DOM 元素,用原生方法綁定點(diǎn)擊事件。在點(diǎn)擊事件中,將state中的count加1,并在此之后打印count的值,結(jié)果會(huì)打印最新的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>當(dāng)前計(jì)數(shù):{this.state.count}</div>
<button id="btn">add</button>
</>
);
}
2. setTimeout
如下代碼,在生命周期componentDidMount函數(shù)中寫了一個(gè)定時(shí)器setTimeout,在setTimeout內(nèi)部將state中的count加1,并在此之后打印count的值,結(jié)果會(huì)打印最新的count值1。
setState雖然也是寫在生命周期componentDidMount函數(shù)中的,但并不是直接寫在componentDidMount里,而是套了一層setTimeout。這樣,setState就表現(xiàn)出同步的形式。
state = { count: 0 };
componentDidMount() {
setTimeout(() => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 1
}, 0);
}
render() {
return (
<>
<div>當(dāng)前計(jì)數(shù):{this.state.count}</div>
<button>add</button>
</>
);
}
4. setState的第二個(gè)參數(shù)
無論setState的對象式寫法,還是函數(shù)式寫法,都有第二個(gè)參數(shù),為可選的回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)在狀態(tài)更新完畢、界面也更新后(render調(diào)用后)才被調(diào)用。
如下代碼所示,setState雖然直接在componentDidMount中調(diào)用,但在setState的回調(diào)函數(shù)中打印count的值,得到了最新的值1,因?yàn)榛卣{(diào)函數(shù)在狀態(tài)更新完畢后才被調(diào)用,當(dāng)然能得到最新的count了。
state = { count: 0 };
componentDidMount() {
this.setState({ count: this.state.count + 1 }, () => {
console.log(this.state.count); // 1
});
}
render() {
return (
<>
<div>當(dāng)前計(jì)數(shù):{this.state.count}</div>
<button>add</button>
</>
);
}
到此這篇關(guān)于關(guān)于React中setState同步或異步問題的理解的文章就介紹到這了,更多相關(guān)React中setState同步或異步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React-hook-form-mui基本使用教程(入門篇)
react-hook-form-mui可以幫助開發(fā)人員更輕松地構(gòu)建表單,它結(jié)合了React?Hook?Form和Material-UI組件庫,使用react-hook-form-mui,開發(fā)人員可以更快速地構(gòu)建表單,并且可以輕松地進(jìn)行表單驗(yàn)證和數(shù)據(jù)處理,本文介紹React-hook-form-mui基本使用,感興趣的朋友一起看看吧2024-02-02
使用React Profiler進(jìn)行性能優(yōu)化方案詳解
在現(xiàn)代前端開發(fā)中,性能優(yōu)化是一個(gè)不可忽視的重要環(huán)節(jié),在 React 生態(tài)系統(tǒng)中,React Profiler 是一個(gè)強(qiáng)大的工具,下面我們來看看如何使用它來提升我們的 React 應(yīng)用吧2025-03-03
React實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的彈框組件
這篇文章主要為大家詳細(xì)介紹了React實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的彈框組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08

