国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

React 中 setState() 為什么是異步的?

anonymoussf / 542人閱讀

摘要:正文在回復中表示為什么是異步的,這并沒有一個明顯的答案,每種方案都有它的權衡。需要注意的是,異步更新是有可能實現這種設想的前提。

前言

不知道大家有沒有過這個疑問,React 中 setState() 為什么是異步的?我一度認為 setState() 是同步的,知道它是異步的之后很是困惑,甚至期待 React 能出一個 setStateSync() 之類的 API。同樣有此疑問的還有 MobX 的作者 Michel Weststrate,他認為經常聽到的答案都很容易反駁,并認為這可能是一個歷史包袱,所以開了一個 issue 詢問真正的原因。最終這個 issue 得到了 React 核心成員 Dan Abramov 的回復,Dan 的回復表明這不是一個歷史包袱,而是一個經過深思熟慮的設計。

注意:這篇文章根據 Dan 的回復寫成,但不是一篇翻譯。我忽略了很多不太重要的內容,Dan 的完整回復請看這里。

正文

Dan 在回復中表示為什么 setState() 是異步的,這并沒有一個明顯的答案(obvious answer),每種方案都有它的權衡。但是 React 的設計有以下幾點考量:

一、保證內部的一致性

首先,我想我們都同意推遲并批量處理重渲染是有益而且對性能優化很重要的,無論 setState() 是同步的還是異步的。那么就算讓 state 同步更新,props 也不行,因為當父組件重渲染(re-render )了你才知道 props

現在的設計保證了 React 提供的 objects(state,props,refs)的行為和表現都是一致的。為什么這很重要?Dan 舉了個栗子:

假設 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

然而,這時你需要將狀態提升到父組件,以供多個兄弟組件共享:

-this.setState({ value: this.state.value + 1 });
+this.props.onIncrement(); // 在父組件中做同樣的事

需要指出的是,在 React 應用中這是一個很常見的重構,幾乎每天都會發生。

然而下面的代碼卻不能按預期工作:

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 (也就是立即重渲染父組件),就必須放棄批處理(根據情況的不同,性能可能會有顯著的下降)。

所以為了解決這樣的問題,在 React 中 this.statethis.props 都是異步更新的,在上面的例子中重構前跟重構后都會打印出 0。這會讓狀態提升更安全。

最后 Dan 總結說,React 模型更愿意保證內部的一致性和狀態提升的安全性,而不總是追求代碼的簡潔性。

二、性能優化

我們通常認為狀態更新會按照既定順序被應用,無論 state 是同步更新還是異步更新。然而事實并不一定如此。

React 會依據不同的調用源,給不同的 setState() 調用分配不同的優先級。調用源包括事件處理、網絡請求、動畫等。

Dan 又舉了個栗子。假設你在一個聊天窗口,你正在輸入消息,TextBox 組件中的 setState() 調用需要被立即應用。然而,在你輸入過程中又收到了一條新消息。更好的處理方式或許是延遲渲染新的 MessageBubble 組件,從而讓你的輸入更加順暢,而不是立即渲染新的 MessageBubble 組件阻塞線程,導致你輸入抖動和延遲。

如果給某些更新分配低優先級,那么就可以把它們的渲染分拆為幾個毫秒的塊,用戶也不會注意到。

三、更多的可能性

Dan 最后說到,異步更新并不只關于性能優化,而是 React 組件模型能做什么的一個根本性轉變(fundamental shift)。

Dan 還是舉了個栗子。假設你從一個頁面導航到到另一個頁面,通常你需要展示一個加載動畫,等待新頁面的渲染。但是如果導航非常快,閃爍一下加載動畫又會降低用戶體驗。

如果這樣會不會好點,你只需要簡單的調用 setState() 去渲染一個新的頁面,React “在幕后”開始渲染這個新的頁面。想象一下,不需要你寫任何的協調代碼,如果這個更新花了比較長的時間,你可以展示一個加載動畫,否則在新頁面準備好后,讓 React 執行一個無縫的切換。此外,在等待過程中,舊的頁面依然可以交互,但是如果花費的時間比較長,你必須展示一個加載動畫。

事實證明,在現在的 React 模型基礎上做一些生命周期調整,真的可以實現這種設想。@acdlite 已經為這個功能努力幾周了,并且很快會發布一個 RFC(亦可賽艇!)。

需要注意的是,異步更新 state 是有可能實現這種設想的前提。如果同步更新 state 就沒有辦法在幕后渲染新的頁面,還保持舊的頁面可以交互。它們之間獨立的狀態更新會沖突。

Dan 最后對 Michel 說到:我希望我們能在接下來幾個月說服你,并且你會欣賞到 React 模型的靈活性。據我理解,這種靈活性至少一部分要歸功于 state 的異步更新。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107054.html

相關文章

  • setState異步、同步與進階

    摘要:根本原因在于,并不是真正意義上的異步操作,它只是模擬了異步的行為。而合成事件和生命周期函數中,是受控制的,其會將設置為,從而走的是類似異步的那一套。總結此處總結是直接引用了只在合成事件和鉤子函數中是異步的,在原生事件和中都是同步的。 如何使用setState 在 React 日常的使用中,一個很重要的點就是,不要直接去修改 state。例如:this.state.count = 1是無...

    widuu 評論0 收藏0
  • React-setState雜記

    摘要:簡單的舉下例子如等生命周期以及的事件即為異步更新,這里不顯示具體代碼。因為只有當父組件后才傳給子組件,那么如果要變成同步的,就需要放棄。 前言 在看React的官方文檔的時候, 發現了這么一句話,State Updates May Be Asynchronous,于是查詢了一波資料, 最后歸納成以下3個問題 setState為什么要異步更新,它是怎么做的? setState什么時候會...

    yuxue 評論0 收藏0
  • 關于ReactsetState

    摘要:而在第二個參數中我們輸出了改變后的即第五行輸出,表明我們的更改生效了。而在的回調內,我們還調用了一個定義于內的事件函數,但是該事件函數內的也是同步的形式。 在react中,setState是用以改變class組件狀態的函數,它有兩種用法:一 傳入一個updater函數,該函數有兩個參數,一個是當前的state,還有一個是當前的props。該函數的返回值需要是一個更改的state值的對象...

    qieangel2013 評論0 收藏0
  • ReactsetState異步

    摘要:在學習的過程中幾乎所有學習材料都會反復強調一點是異步的來看一下官網對于的說明。將認為是一次請求而不是一次立即執行更新組件的命令。總結在組件生命周期中或者事件綁定中,是通過異步更新的。在延時的回調或者原生事件綁定的回調中調用不一定是異步的。 在學習react的過程中幾乎所有學習材料都會反復強調一點setState是異步的,來看一下react官網對于setState的說明。 將setSta...

    hankkin 評論0 收藏0
  • React專題:可變狀態

    摘要:的參數既可以是一個對象,也可以是一個回調函數。回調函數提供了兩個參數,第一個參數就是計算過的對象,即便這時還沒有渲染,得到的依然是符合直覺的計算過的值。專題一覽什么是可變狀態不可變屬性生命周期組件事件操作抽象 本文是『horseshoe·React專題』系列文章之一,后續會有更多專題推出來我的 GitHub repo 閱讀完整的專題文章來我的 個人博客 獲得無與倫比的閱讀體驗 Reac...

    hosition 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<