摘要:正文在回復中表示為什么是異步的,這并沒有一個明顯的答案,每種方案都有它的權(quán)衡。需要注意的是,異步更新是有可能實現(xiàn)這種設(shè)想的前提。
前言
不知道大家有沒有過這個疑問,React 中 setState() 為什么是異步的?我一度認為 setState() 是同步的,知道它是異步的之后很是困惑,甚至期待 React 能出一個 setStateSync() 之類的 API。同樣有此疑問的還有 MobX 的作者 Michel Weststrate,他認為經(jīng)常聽到的答案都很容易反駁,并認為這可能是一個歷史包袱,所以開了一個 issue 詢問真正的原因。最終這個 issue 得到了 React 核心成員 Dan Abramov 的回復,Dan 的回復表明這不是一個歷史包袱,而是一個經(jīng)過深思熟慮的設(shè)計。
注意:這篇文章根據(jù) Dan 的回復寫成,但不是一篇翻譯。我忽略了很多不太重要的內(nèi)容,Dan 的完整回復請看這里。
正文Dan 在回復中表示為什么 setState() 是異步的,這并沒有一個明顯的答案(obvious answer),每種方案都有它的權(quán)衡。但是 React 的設(shè)計有以下幾點考量:
一、保證內(nèi)部的一致性首先,我想我們都同意推遲并批量處理重渲染是有益而且對性能優(yōu)化很重要的,無論 setState() 是同步的還是異步的。那么就算讓 state 同步更新,props 也不行,因為當父組件重渲染(re-render )了你才知道 props。
現(xiàn)在的設(shè)計保證了 React 提供的 objects(state,props,refs)的行為和表現(xiàn)都是一致的。為什么這很重要?Dan 舉了個栗子:
假設(shè) state 是同步更新的,那么下面的代碼是可以按預期工作的:
console.log(this.state.value) // 0 this.setState({ value: this.state.value + 1 }); console.log(this.state.value) // 1 this.setState({ value: this.state.value + 1 }); console.log(this.state.value) // 2
然而,這時你需要將狀態(tài)提升到父組件,以供多個兄弟組件共享:
-this.setState({ value: this.state.value + 1 }); +this.props.onIncrement(); // 在父組件中做同樣的事
需要指出的是,在 React 應(yīng)用中這是一個很常見的重構(gòu),幾乎每天都會發(fā)生。
然而下面的代碼卻不能按預期工作:
console.log(this.props.value) // 0 this.props.onIncrement(); console.log(this.props.value) // 0 this.props.onIncrement(); console.log(this.props.value) // 0
這是因為同步模型中,雖然 this.state 會立即更新,但是 this.props 并不會。而且在沒有重渲染父組件的情況下,我們不能立即更新 this.props。如果要立即更新 this.props (也就是立即重渲染父組件),就必須放棄批處理(根據(jù)情況的不同,性能可能會有顯著的下降)。
所以為了解決這樣的問題,在 React 中 this.state 和 this.props 都是異步更新的,在上面的例子中重構(gòu)前跟重構(gòu)后都會打印出 0。這會讓狀態(tài)提升更安全。
最后 Dan 總結(jié)說,React 模型更愿意保證內(nèi)部的一致性和狀態(tài)提升的安全性,而不總是追求代碼的簡潔性。
二、性能優(yōu)化我們通常認為狀態(tài)更新會按照既定順序被應(yīng)用,無論 state 是同步更新還是異步更新。然而事實并不一定如此。
React 會依據(jù)不同的調(diào)用源,給不同的 setState() 調(diào)用分配不同的優(yōu)先級。調(diào)用源包括事件處理、網(wǎng)絡(luò)請求、動畫等。
Dan 又舉了個栗子。假設(shè)你在一個聊天窗口,你正在輸入消息,TextBox 組件中的 setState() 調(diào)用需要被立即應(yīng)用。然而,在你輸入過程中又收到了一條新消息。更好的處理方式或許是延遲渲染新的 MessageBubble 組件,從而讓你的輸入更加順暢,而不是立即渲染新的 MessageBubble 組件阻塞線程,導致你輸入抖動和延遲。
如果給某些更新分配低優(yōu)先級,那么就可以把它們的渲染分拆為幾個毫秒的塊,用戶也不會注意到。
三、更多的可能性Dan 最后說到,異步更新并不只關(guān)于性能優(yōu)化,而是 React 組件模型能做什么的一個根本性轉(zhuǎn)變(fundamental shift)。
Dan 還是舉了個栗子。假設(shè)你從一個頁面導航到到另一個頁面,通常你需要展示一個加載動畫,等待新頁面的渲染。但是如果導航非常快,閃爍一下加載動畫又會降低用戶體驗。
如果這樣會不會好點,你只需要簡單的調(diào)用 setState() 去渲染一個新的頁面,React “在幕后”開始渲染這個新的頁面。想象一下,不需要你寫任何的協(xié)調(diào)代碼,如果這個更新花了比較長的時間,你可以展示一個加載動畫,否則在新頁面準備好后,讓 React 執(zhí)行一個無縫的切換。此外,在等待過程中,舊的頁面依然可以交互,但是如果花費的時間比較長,你必須展示一個加載動畫。
事實證明,在現(xiàn)在的 React 模型基礎(chǔ)上做一些生命周期調(diào)整,真的可以實現(xiàn)這種設(shè)想。@acdlite 已經(jīng)為這個功能努力幾周了,并且很快會發(fā)布一個 RFC(亦可賽艇!)。
需要注意的是,異步更新 state 是有可能實現(xiàn)這種設(shè)想的前提。如果同步更新 state 就沒有辦法在幕后渲染新的頁面,還保持舊的頁面可以交互。它們之間獨立的狀態(tài)更新會沖突。
Dan 最后對 Michel 說到:我希望我們能在接下來幾個月說服你,并且你會欣賞到 React 模型的靈活性。據(jù)我理解,這種靈活性至少一部分要歸功于 state 的異步更新。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107054.html
摘要:根本原因在于,并不是真正意義上的異步操作,它只是模擬了異步的行為。而合成事件和生命周期函數(shù)中,是受控制的,其會將設(shè)置為,從而走的是類似異步的那一套。總結(jié)此處總結(jié)是直接引用了只在合成事件和鉤子函數(shù)中是異步的,在原生事件和中都是同步的。 如何使用setState 在 React 日常的使用中,一個很重要的點就是,不要直接去修改 state。例如:this.state.count = 1是無...
摘要:簡單的舉下例子如等生命周期以及的事件即為異步更新,這里不顯示具體代碼。因為只有當父組件后才傳給子組件,那么如果要變成同步的,就需要放棄。 前言 在看React的官方文檔的時候, 發(fā)現(xiàn)了這么一句話,State Updates May Be Asynchronous,于是查詢了一波資料, 最后歸納成以下3個問題 setState為什么要異步更新,它是怎么做的? setState什么時候會...
摘要:而在第二個參數(shù)中我們輸出了改變后的即第五行輸出,表明我們的更改生效了。而在的回調(diào)內(nèi),我們還調(diào)用了一個定義于內(nèi)的事件函數(shù),但是該事件函數(shù)內(nèi)的也是同步的形式。 在react中,setState是用以改變class組件狀態(tài)的函數(shù),它有兩種用法:一 傳入一個updater函數(shù),該函數(shù)有兩個參數(shù),一個是當前的state,還有一個是當前的props。該函數(shù)的返回值需要是一個更改的state值的對象...
摘要:在學習的過程中幾乎所有學習材料都會反復強調(diào)一點是異步的來看一下官網(wǎng)對于的說明。將認為是一次請求而不是一次立即執(zhí)行更新組件的命令。總結(jié)在組件生命周期中或者事件綁定中,是通過異步更新的。在延時的回調(diào)或者原生事件綁定的回調(diào)中調(diào)用不一定是異步的。 在學習react的過程中幾乎所有學習材料都會反復強調(diào)一點setState是異步的,來看一下react官網(wǎng)對于setState的說明。 將setSta...
摘要:的參數(shù)既可以是一個對象,也可以是一個回調(diào)函數(shù)。回調(diào)函數(shù)提供了兩個參數(shù),第一個參數(shù)就是計算過的對象,即便這時還沒有渲染,得到的依然是符合直覺的計算過的值。專題一覽什么是可變狀態(tài)不可變屬性生命周期組件事件操作抽象 本文是『horseshoe·React專題』系列文章之一,后續(xù)會有更多專題推出來我的 GitHub repo 閱讀完整的專題文章來我的 個人博客 獲得無與倫比的閱讀體驗 Reac...
閱讀 996·2023-04-25 14:45
閱讀 2772·2021-09-30 09:59
閱讀 3114·2021-09-22 15:48
閱讀 2425·2019-08-30 15:55
閱讀 3467·2019-08-30 15:44
閱讀 535·2019-08-29 14:07
閱讀 3412·2019-08-26 13:45
閱讀 536·2019-08-26 11:31