在網(wǎng)上看了很多關(guān)于this.setState()
的介紹,覺得受益匪淺,就總結(jié)了一些幫助自己理解的點讼稚,在此分享出來撩荣,如果有侵權(quán)的地方,請及時提醒田晚。
一、State的定義
狀態(tài)(state
) 和 屬性(props
) 類似,都是一個組件所需要的一些數(shù)據(jù)集合滤淳,但是它是私有的,并且由組件本身完全控制砌左,可以認為它是組件的“私有屬性(或者是局部屬性)”脖咐。
二、關(guān)于 setState() 有三件事是你應(yīng)該知道的汇歹。# 參考鏈接
1.不要直接修改 state(狀態(tài))
this.state.comment = 'Hello';
上述代碼并不會重新渲染組件屁擅,需要使用this.setState()代替:
this.setState({
comment: 'Hello'
});
需要注意的是唯一可以分配 this.state 的地方是構(gòu)造函數(shù)。
2.state(狀態(tài)) 更新可能是異步的
React 為了優(yōu)化性能产弹,有可能會將多個 setState() 調(diào)用合并為一次更新派歌。
因為this.props
和this.state
可能是異步更新的,你不能依賴他們的值計算下一個state
(狀態(tài))痰哨。以下面的代碼為例:
this.setState({
counter: this.state.counter + this.props.increment,
});
我們并不能通過上述代碼得到想要的值胶果,為了彌補這個問題,使用另一種 setState() 的形式斤斧,接受一個函數(shù)早抠。這個函數(shù)將接收前一個狀態(tài)作為第一個參數(shù),應(yīng)用更新時的 props 作為第二個參數(shù)折欠,代碼如下:
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
3.state(狀態(tài))更新會被合并
當你調(diào)用 setState()贝或, React 將合并你提供的對象到當前的狀態(tài)中吼过。所以當State是一個多鍵值的結(jié)構(gòu)時,可以單獨更新其中的一個咪奖,此時會進行“差分”更新盗忱,不會影響其他的屬性值。
三羊赵、setState()的異步更新趟佃。# 原文鏈接
1.執(zhí)行setState()之后干了什么?
setState()
方法通過一個隊列機制實現(xiàn)state
更新昧捷,當執(zhí)行setState()
的時候闲昭,會將需要更新的state
合并之后放入狀態(tài)隊列,而不會立即更新this.state
(可以和瀏覽器的事件隊列類比)靡挥。如果我們不使用setState
而是使用this.state.key
來修改序矩,將不會觸發(fā)組件的re-render
。如果將this.state
賦值給一個新的對象引用跋破,那么其他不在對象上的state
將不會被放入狀態(tài)隊列中簸淀,當下次調(diào)用setState()
并對狀態(tài)隊列進行合并時,直接造成了state
丟失毒返。
2.setState()可以接受一個函數(shù)作為參數(shù)租幕?
setState()
不僅能夠接受一個對象作為參數(shù),還能夠接受一個函數(shù)作為參數(shù)拧簸。函數(shù)的參數(shù)即為 state
的前一個狀態(tài)以及 props
劲绪。
React文檔中對setState的說明如下:
void setState (
function|object nextState,
[function callback]
)
上述代碼的第二個參數(shù)是一個回調(diào)函數(shù),在setState()
的異步操作結(jié)束并且組件已經(jīng)重新渲染的時候執(zhí)行盆赤。換句話說贾富,我們可以通過這個回調(diào)來拿到更新的state
的值。
3.執(zhí)行setState()后能拿到最新的state值嗎弟劲?
以前在寫代碼時候祷安,總是遇到明明執(zhí)行過setState(),但是state的值卻不是最新的兔乞,那么如何解決這個問題呢汇鞭?
因為setState()
函數(shù)接受兩個參數(shù),一個是一個對象庸追,就是設(shè)置的狀態(tài)霍骄,還有一個是一個回調(diào)函數(shù),是在設(shè)置狀態(tài)成功之后執(zhí)行的淡溯,所以我們可以通過回掉拿到最新的state
值读整。代碼如下:
updateData = (newData) => {
this.setState(
{ data: newData },
() => {
//這里打印的是最新的state值
console.log(this.state.data);
}
);
}
4.setState()一定是異步更新嗎? **# 原文鏈接
我們先來看看下面的代碼:
function incrementMultiple() {
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
}
直觀上來看咱娶,當上面的 incrementMultiple 函數(shù)被調(diào)用時米间,組件狀態(tài)的 count 值被增加了3次强品,每次增加1,那最后 count 被增加了3屈糊。但是的榛,實際上的結(jié)果只給 state 增加了1。
事實上逻锐,setState 方法與包含在其中的執(zhí)行是一個很復(fù)雜的過程夫晌,從 React 最初的版本到現(xiàn)在,也有無數(shù)次的修改昧诱。它的工作除了要更動 this.state 之外晓淀,還要負責觸發(fā)重新渲染,這里面要經(jīng)過 React 核心 diff 算法盏档,最終才能決定是否要進行重渲染凶掰,以及如何渲染。而且為了批次與效能的理由妆丘,多個 setState 呼叫有可能在執(zhí)行過程中還需要被合并锄俄,所以它被設(shè)計以延時的來進行執(zhí)行是相當合理的。
在 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宦言。
作者給出了下面的重點,趕緊拿起我的小本本記下商模。
由 React 控制的事件處理過程 setState 不會同步更新 this.state奠旺!
也就是說,在 React 控制之外的情況施流, setState 會同步更新 this.state响疚!
在大部分的使用情況下,我們都是使用了 React 庫中的表單組件瞪醋,例如 select忿晕、input、button 等等银受,它們都是 React 庫中人造的組件與事件践盼,是處于 React 庫的控制之下鸦采,比如組件原色 onClick 都是經(jīng)過 React 包裝。在這個情況下咕幻,setState 就會以異步的方式執(zhí)行渔伯。
總結(jié)就到這里了,由于我是技術(shù)渣渣谅河,能看懂和理解的只有這么多了咱旱,如果有讀者還想了解更多的內(nèi)容,可以點擊我文中的原文鏈接去看原作者的文章绷耍,如果遇到侵權(quán)的地方吐限,請聯(lián)系我,必刪褂始。