掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流
想起自己(2021年) 8 月份面試時,被面試官們問了好幾個 setState 的問題,現(xiàn)在想想,雖然回答上問題,但是了解得不深刻。我知道 setState 被設計成“異步”是為了性能,但是涉及到源碼解讀我就歇菜了;我知道如何讓它同步,但是遇到真實的代碼情況時,卻不知道如何下手。說到底,當時是準備了面經(jīng)把這些概念記下來,而沒有真正理解它

關嶺ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
在認識 setState 前,我們問幾個常見問題
React 的理念之一是 UI=f(data),修改 data 即驅(qū)動 UI 變化,那么怎么修改呢?React 提供了一個 API ——setState(類組件的修改方法)
官網(wǎng)介紹:
setState(updater, [callback])
參數(shù)一為帶有形式參數(shù)的 updater 函數(shù):
(state, props) => stateChange
// 例如
// this.setState((state, props) => {
// return {counter: state.counter + props.step};
// });
setState 的第一個參數(shù)除了接受函數(shù)外,還可以接受對象類型:
setState(stateChange[, callback])
// 例如:this.setState({count: 2})
setState 的第二個參數(shù)為可選的回調(diào)函數(shù),它將在 setState 完成合并重新渲染組件后執(zhí)行。通常,我們建議使用 componentDidUpdate 來代替此方法
setState(stateChange[, callback])
// 例如: this.setState({count: 2}, () => {console.log(this.state.count)})
stackoverflow 有人問過,也有人回答過:
setState 的特性——批處理
如果在同一周期內(nèi)對多個 setState 進行處理,例如,在同一周期內(nèi)多次設置商品數(shù)據(jù),相當于:
this.setState({count: state.count + 1});
this.setState({count: state.count + 1});
this.setState({count: state.count + 1});
// ===
Object.assign(
count,
{quantity: state.quantity + 1},
{quantity: state.quantity + 1},
...
)
后調(diào)的 setState 將覆蓋同一周期內(nèi)先調(diào)用 setState 的值
setState 必引發(fā)更新過程,但不一定會引發(fā) render 被執(zhí)行,因為 shouldCompomentUpdate 可以返回 false
state.count = 0;
this.setState({count: state.count + 1});
this.setState({count: state.count + 1});
this.setState({count: state.count + 1});
// state.count === 1,不是 3
因為 this.setState 方法為會進行批處理,后調(diào)的 setState 會覆蓋統(tǒng)一周期內(nèi)先調(diào)用的 setState 的值,如下圖所示:
state.count = 0;
this.setState({count: state.count + 2});
this.setState({count: state.count + 3});
this.setState({count: state.count + 4});
// state.count === 4
因為 setState 做的事情不僅僅只是修改了 this.state 的值,另外最重要的是它會觸發(fā) React 的更新機制,會進行diff,然后將 patch 部分更新到真實 dom 里
如果你直接 this.state.xx = oo 的話,state 的值確實會改,但是它不會驅(qū)動 React 重渲染。setState 能幫助我們更新視圖,引發(fā) shouldComponentUpdate、render 等一系列函數(shù)的調(diào)用。至于批處理,React 會將 setState 的效果放入隊列中,在事件結束之后產(chǎn)生一次重新渲染,為的就是把 Virtual DOM 和 DOM 樹操作降到最小,用于提高性能
當調(diào)用 setState 后,React 的 生命周期函數(shù) 會依次順序執(zhí)行
因為性能優(yōu)化。假如每次 setState 都要更新數(shù)據(jù),更新過程就要走五個生命周期,走完一輪生命周期再拿 render 函數(shù)的結果去做 diff 對比和更新真實 DOM,會很耗時間。所以將每次調(diào)用都放一起做一次性處理,能降低對 DOM 的操作,提高應用性能
通過第二個參數(shù) setState(partialState, callback) 中的 callback 拿到更新后的結果
onHandleClick() {
this.setState(
{
count: this.state.count + 1,
},
() => {
console.log("點擊之后的回調(diào)", this.state.count); // 最新值
}
);
}
或者可以直接給 state 傳遞函數(shù)來表現(xiàn)出同步的情況
this.setState(state => {
console.log("函數(shù)模式", state.count);
return { count: state.count + 1 };
});
首先先了解三種渲染模式
在 legacy 模式下,在 React 的 setState 函數(shù)實現(xiàn)中,會根據(jù)一個變量 isBatchingUpdates 判斷是直接更新 this.state 還是放到隊列中回頭再說,而 isBatchingUpdates 默認是 false,也就表示 setState 會同步更新 this.state,但是,有一個函數(shù) batchedUpdates,這個函數(shù)會把 isBatchingUpdates 修改為 true,而當 React 在調(diào)用事件處理函數(shù)之前就會調(diào)用這個 batchedUpdates,造成的后果,就是由 React 控制的事件處理過程 setState 不會同步更新 this.state
像 addEventListener 綁定的原生事件、setTimeout/setInterval 會走同步,除此之外,也就是 React 控制的事件處理 setState 會異步
而 concurrent 模式都是異步,這也是未來 React 18 的默認模式
首先,我們總結下關鍵知識點
其次,回答一下文章開頭的問題(第二第三問題在文中已經(jīng)回答)
setState 是同步還是異步?

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流