React 18 帶給我們的驚喜

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列

這篇文章發布于3.28日,3.29日 react 18 發布。

1、前言

React 18 的 alpha 版已經發布有段時間了,之前學習后由于沒有開發實踐結合去思考,對 React 18 的意義認識并不深刻。前段時間做了一些老舊項目遷移,發現復雜項目下每次渲染都要精心調整,否則就會有麻煩的性能或體驗瑕疵,而 React 內部渲染順序和優先級很難調整,就導致總體體驗差了點意思。回顧了 React 18 的三個新特性,有種久旱逢甘雨的欣喜。

團隊內部推行了 React hook,好處就不在這里贅述了,也陸續收到了一些負面反饋。其一就是 React hook 更加趨向面向數據實體進行拆分,而一個動作需要多個數據實體協作,例如一個 Modal Form 需要 visible 和 data 兩個數據項協作,但是這兩個數據項的變更會觸發兩次渲染結算,增加性能開銷。

作者之前遇到過復雜 Form 表單下,初次渲染由于數據項過于復雜導致無限次 render 的 bug。在這個 case 中,核心的沖突就是在數據項復雜度提升的同時,React Diff 的性能就遇到了“偽瓶頸”。這里不是說 React Diff 性能差,僅僅想表達它的高性能需要更高的設計理念和實踐經驗,這也是相對于 Vue 等更加易學的框架而言,總的來說上限高下限也低。而 React 18 的變化讓我看到了 React 團隊正在關注這一部分,并且給予了更好的解決方案。

閑聊到此為止,進入正題,給大家介紹下 React 18 的四個重要新特性:

  • Automatic batching

  • Concurrent APIS

  • SSR for Suspense

  • New Render API

2、Automatic batching

在 React 中使用 setState 來進行 dispatch 組件 State 變化,當 setState 在組件被調用后,并不會立即觸發重新渲染。React 會執行全部事件處理函數,然后觸發一個單獨的 re-render,合并所有更新。這里舉個簡單例子:

const [count, setCount] = useState(0);function increment() {// setCount(count + 1)// 使用無狀態函數進行優化,避免多次 re-rendersetCount(c => c + 1);
}function handleClick() {increment();increment();increment();
}

最終 React 會將更新函數放到一個隊列里,然后合并隊列觸發 setCount (3) 的 re-render,這就是 batching 的含義。

這樣既可以減少程序數據狀態存在中間值導致的不穩定性,也可以提升渲染性能。但是可惜的是在 React 18 之前,如果在回調函數的異步調用中,執行 setState,由于丟失了上下文,無法做合并處理,所以每次 setState 調用都會觸發一次 re-render。

function handleClick() {// React 18 以前的版本(/*...*/).then(() => {setCount((c) => c + 1); // 立刻重渲染setFlag((f) => !f); // 立刻重渲染});
}

而 React 18 帶來變化便是,任何情況下都可以合并渲染了!

如果你希望在 React 18 的 setState 后立即執行重新渲染, 只需要使用 flushSync 包裹即可。

function handleClick() {// React 18+fetch(/*...*/).then(() => {ReactDOM.flushSync(() => {setCount((c) => c + 1); // 立刻重渲染setFlag((f) => !f); // 立刻重渲染});});
}

回歸到實際開發中,Automatic batching 機制讓我們有能力對渲染順序和節奏進行一些基礎的把控。例如在 Canvas 畫布編輯場景中,我們可以加載完主節點框架之后立刻進行渲染,而每個節點的內容則可以進行合并渲染,盡可能加快用戶看到可編輯頁面的時間,同時避免 http 異步函數引起的頻繁渲染的性能開銷。

cd12778142653bb75949754ab0be5edd.png

3、Concurrent APIS

在官方視頻中明確指出了 React 18 中并不存在 Concurrent Mode,只有用于并發渲染的并發新特性。開發者希望能夠在 Web Platform 引入并發渲染,來實現多個渲染任務的并行渲染,其中 Suspense 就是基于此誕生的。

React 18 提供了三個新的 API 支持這一并發特性,分別是:

  • startTransition()

  • useDeferredValue()

  • useTransition()

由于 useTransition 的官方文檔并未放出來,這里就僅僅介紹另外兩種 API。

3.1 startTransition()

import { startTransition } from "react";// 緊急更新:
setInputValue(input);// 標記回調函數內的更新為非緊急更新:
startTransition(() => {setSearchQuery(input);
});

簡單來說,被 startTransition 包裹的 setState 觸發的渲染被標記為不緊急渲染,意味著他們可以被其他緊急渲染所搶占。這種渲染優先級的調整手段可以幫助我們解決各種性能偽瓶頸,提升用戶體驗。

3.2 useDeferredValue()

這個 hook 適用于設置延遲值,參考官方演示視頻來看。

function Page() {const [filters, mergeFilter] = useMergeState(defaultFilters);const deferedFilters = React.useDeferedValue(filters);return (<Fragment><Filters filters={filters} ><List filters={deferedFilters} ></Fragment>);
}

useDeferedValue () 會將 List 組件的渲染變得更加平滑,深層次來看則是 defered value 引起的渲染則會被標記為不緊急渲染,會被 filters 引起的渲染進行搶占,進而達到用戶快速輸入搜索等場景下頁面抖動或者卡頓問題。

4、SSR for Suspense

早在 2018 年,React 就推出了 Suspense 的基礎版本。

e728a70775d315ae4e266cccec742bee.png

它可以在客戶端動態加載代碼(React.lazy),配合 Suspense 組件實現數據拉取和狀態控制的關注點分離(當子組件未加載完成時,父組件填充 fallback 聲明的組件),但是并不能在服務器端進行加載。

<Suspense fallback={<Skeleton />}><Header /><Suspense fallback={<ListPlaceholder />}><ListLayout /></Suspense>
</Suspense>

React 的開發者對 Suspense 的期望并不僅僅止步于此,他們認為 Suspense 拓展了我們對組件的概念。在 React 18 中,Suspense 可以運行在服務器端,Server Rendering 的性能不需要受制于性能最差的組件(木桶效應)。

在 React 18 之前,Server Rendering 的流程是服務器端請求所有數據,然后發送 HTML 到客戶端或者說瀏覽器,然后由客戶端的 hydrate 內容,每個環節必須按部就班的執行。當 Suspense 可以在服務器端使用之后,一旦某個組件加載慢,就可以將 fallback 的內容傳輸到客戶端(例如下圖中的 loading 態),保證用戶盡可能早的可進行交互。

c79ce29ccb0d46daa83c7f4b643c4cc8.png

更加優秀的部分則是,hydrate 是可以通過用戶的行為來調整優先級的,例如上圖中 Profile 組件和正在 Loading 的評論組件同時處于 Suspense 的流程中,此時用戶點擊評論組件,React 將會優先 hydrate 評論組件,盡可能優先滿足用戶交互體驗。

回歸到代碼實現細節,整體框架上服務器和客戶端的連接必然趨向于持續性的長鏈接,因此 res.send 需要變成 res.socket,pipeToNodeWritable 替換 renderToString 并且配合 Suspense 即可(官方例子)。

5、New Render API

新的更加友好的語義化 render 方式。

const container = document.getElementById("app");// 舊 render API
ReactDOM.render(<App />, container);// 新 createRoot API
const root = ReactDOM.createRoot(container);
root.render(<App />);

Client 端提供了新 水合 Hydrate API。

const root = ReactDOM.hydrateRoot(container, <App tab="home" />);

以及 新 useId () API 來為組件生成唯一 ID。

由于 Suspense 和 并發渲染在 React 18 的大規模使用,一些具有 External stores 的 API,比如全局變量、document 對象如何在并發場景下保證一致性呢?如果無法保證一致性,在并發渲染過程中可能會導致組件展示的不一致。

ef3976f1f0bb14f9f07b70973e5e4708.png

為了解決這個問題,React 18 提供了 useSyncExternalStore() 這個 hook,來保證獲取 External stores 的一致性。

useSyncExternalStore(// 注冊回調函數subscribe: (callback) => Unsubscribe,// 獲取快照函數getSnapshot: () => state
) => state

具體使用方式參考:

ec7f01a1a3a89fc5a562207c20ca58ba.png

6、React 未來展望

在官方視頻中,開發者們也對未來版本的內容進行介紹。

Support for Data Fetching API

由于 Suspense 的大規模應用,其數據獲取變得更加定制化,目前常見的有 Relay、React Query 等。React 官方也希望將這一部分納入到 React 的 API 中。

Server Component

組件不僅可以通過網絡讀取數據、也可以后臺數據層直接讀取服務數據,將大大減少服務器端向客戶端傳輸的代碼量,和同構模式十分類似。

React 18 in React Native

2022 年 React 18 將和 React Native 一起發布,跨平臺構建的史詩級更新,RN 并發的一些老大難將得到解決。

7、結語

結合起來看,React 18 關注點在于更快的性能、用戶交互響應效率和跨平臺構建,其設計理念處處包含了中斷與搶占概念。React 18 給我們提供了一些從應用構建視角下的手段,例如:

  1. 在 Client 端隨時中斷的框架設計,第一優先級渲染用戶最關注的 UI 交互模塊。

  2. 從后端到前端 “順滑” 的管道式 SSR,并將 hydration 過程按需化,且支持被更高優先級用戶交互行為打斷,第一優先水合用戶正在交互的部分。

作為一名前端開發,十分期待 React 18 的到來。

db23d15eac47d11a6d09a998c531d163.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

f665561e27eada368c1325fe044180a4.png

掃碼加我微信 ruochuan02、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274780.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274780.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274780.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

建模心法(2)——邁出建模第一步

原文地址&#xff1a;http://www.cnblogs.com/1-2-3/archive/2008/08/04/model-method-part1.html 原文作者&#xff1a;景春雷 一錯再錯的這故事才精彩 ——樸樹 《我愛你再見》摘要 即使讀了再多的書、跟過再多的項目&#xff0c;…

Web:你知道我這十幾年是怎么過來的嗎?!

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列1989 …

設計師更高效_如何丟掉我的工作使我成為一名更好的設計師

設計師更高效I lost my job a few times early on in my design career. In the process of getting back up after a job loss, it has made me a better designer not only in terms of hard skills but the soft skills required to be more resilient and empathetic, whic…

【ASP.NET】登陸成功后如何跳轉到上一個頁面

當用戶瀏覽網頁的時候會在某個地方需要用戶登陸才能繼續瀏覽&#xff0c;用戶登陸之后會自動跳轉到剛剛瀏覽的頁面。這個步驟是怎么實現的呢&#xff1f;net小伙在查閱相關資料實踐之后終于明白了&#xff0c;其實很簡單&#xff0c;先分享給大家吧。 當用戶在瀏覽一個頁面的時…

4月,誠邀你參加源碼共讀,學會看源碼,打開新世界!開闊視野

大家好&#xff0c;我是若川。很多關注我的新朋友可能不知道我組織了源碼共讀活動~也有很多人不知道我是誰。有人以為我是80后。有人以為我是全職自媒體等等。若川的 2021 年度總結&#xff0c;彈指之間 這篇文章寫了我是16年畢業的&#xff0c;或許有些啟發。源碼共讀按照從易…

bt709和srgb_選擇用于多用途視頻編輯和色彩校正的顯示器— sRGB,DCI-P3,REC 709

bt709和srgb**Note from the author: if you enjoy this article, please follow me or this publication for more video production and marketing related content.****作者注&#xff1a;如果您喜歡本文&#xff0c;請關注我或此出版物以獲取更多與視頻制作和營銷相關的內容…

超4000人參加源碼共讀,喊你來一起學習成長~打開新世界

大家好&#xff0c;我是若川。很多關注我的新朋友可能不知道我組織了源碼共讀活動~也有很多人不知道我是誰。有人以為我是80后。有人以為我是全職自媒體等等。若川的 2021 年度總結&#xff0c;彈指之間 這篇文章寫了我是16年畢業的&#xff0c;或許有些啟發。源碼共讀按照從易…

figma設計_如何在Figma中構建設計入門套件(第二部分)

figma設計Figma教程 (Figma Tutorial) With this short, but informative Tutorial Series I aim to show you how to build the solid foundations of a powerful, and versatile Design Starter Kit, enabling you to start your next project in Figma faster than ever bef…

Hibernate 簡介(百度)

Hibernate是一個開放源代碼的對象關系映射框架&#xff0c;它對JDBC進行了非常輕量級的對象封裝&#xff0c;使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。 Hibernate可以應用在任何使用JDBC的場合&#xff0c;既可以在Java的客戶端程序使用&#xff0c;也可以在…

GitHub 最受歡迎的Top 20 JavaScript 項目

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列今天來…

java反編譯,eclipse支持插件

http://java.decompiler.free.fr/?qjdeclipse 按照說明 在eclipse更新插件就可以。 這樣 在一些 閉源的jar文件&#xff0c;你也可以看到 大致的源碼。&#xff08;公司 知道如何 加密混淆 java代碼或class文件&#xff0c;居然無法使用jd-gui瀏覽源碼&#xff09; 而&#xf…

unity vr 交互_基于手動的VR / MR交互,用于刪除實體

unity vr 交互Deleting an entity or closing an application is one of the most ubiquitous operations performed in any application. It is necessary for the organization of the data. On the computer, there are multiple ways to delete a file like cmd delete, d…

手把手帶你走進Babel的編譯世界

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列前言談…

iPhone/Mac Objective-C內存管理教程和原理剖析(二)口訣與范式轉

版權聲明 此文版權歸作者Vince Yuan (vince.yuan#gmail.com)所有。歡迎非營利性轉載&#xff0c;轉載時必須包含原始鏈接http://vinceyuan.cnblogs.com&#xff0c;且必須包含此版權聲明的完整內容。 版本 1.1 發表于2010-03-08 二 口訣與范式 1 口訣。 1.1 …

同態加密應用_重新設計具有同態性的銀行應用

同態加密應用Catering user preference is undoubtedly a never-ending task. End of the day, it takes all sorts to make a world. For that reason, it is deemed important to design with the accent of communicating core business value, and resolving user needs wi…

(字節/華為/美團)前端面經記錄冷冷清清的金三銀四

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列從畢業…

PHP連接PGSQL

function conn($hostName,$Login,$Password,$dbName,$Port) //建立目標數據庫連接 {$conn &ADONewConnection(postgres8);$conn->debug false; //true時adodb將在頁面顯示debug信息$conn->LogSQL(false); //true時adodb將建立adodb_sqllog表記錄每次sql操作$conn-&…

netflix_Netflix播放按鈕剖析

netflixWe will develop a play pause button similar to the one the Netflix video player has.我們將開發一個類似于Netflix視頻播放器的播放暫停按鈕。 Since Swift has replaced Objective-C as the default development language for iOS, the same will apply to Swift…

TypeScript 終極初學者指南

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列在過去…

繼承與多態(六)

繼承 1.繼承 a。.直接在類的后面加上冒號“&#xff1a;”后面跟基類&#xff0c;就該類就繼承了基類的一切特性了。 b。private類不能被繼承&#xff0c;只有public、protected類能被繼承。 c。private類不里面所有的屬性和方法都不能被外界訪問&#xff0c;只有他自己可以。 …