React 并發(fā)功能體驗(前端的并發(fā)模式)
React 是一個開源 JavaScript 庫,開發(fā)人員使用它來創(chuàng)建基于 Web 和移動的應(yīng)用程序,并且支持構(gòu)建交互式用戶界面和 UI 組件。React 是由 Facebook 軟件工程師 Jordan Walke 創(chuàng)建,React 的第一個版本在七年前問世,現(xiàn)在,F(xiàn)acebook 負責維護。React框架自首次發(fā)布以來,React 的受歡迎程度直線飆升,熱度不減。
2020 年 10 月,React 17 發(fā)布了,但令人驚訝的是——“零新功能”。當然,這并不是真的表示沒有任何新添加的功能,讓廣大程序員使用者興奮。事實上,這個版本為我們帶來了很多重大功能的升級及16版本的bug修復(fù),并推出了:Concurrent Mode 和Suspense。
雖然這兩個功能尚未正式發(fā)布,這些功能已提供給開發(fā)人員進行測試。一旦發(fā)布,它們將改變 React 呈現(xiàn)其 UI 的方式,從而達到雙倍提高性能和用戶體驗。
簡要說明, Concurrent Mode 和Suspense 可以使用戶無縫處理數(shù)據(jù)加載,加載狀態(tài),用戶界面操作更加平滑和無縫切換。 在Concurrent Mode 下,React可以暫停高消耗的,非緊急的組件的渲染,并聚焦在更加緊迫的任務(wù)處理,如UI 渲染,始終保持應(yīng)用為可響應(yīng)式,避免白屏,卡頓等現(xiàn)象。
本文主要分享深入了解Concurrent Mode 和Suspense 模式下的數(shù)據(jù)提取功能。
為什么需要 Concurrent Mode?
眾所周知,JavaScript 框架或庫是單線程的工作。因此,當一個代碼塊運行時,其余的塊必須等待執(zhí)行。無法并發(fā)執(zhí)行多線程工作。界面渲染也是一樣的。
一旦 React 開始渲染某些東西,無法中斷直到運行完成。React 開發(fā)人員將這種渲染稱為“阻塞渲染”。 這種阻塞渲染會創(chuàng)建一個不穩(wěn)定的用戶界面,并且隨時可能停止響應(yīng)。
具體問題
假如,我們需要顯示一個很長的可選列表用于過濾產(chǎn)品的應(yīng)用程序。我們使用搜索框用于過濾記錄,設(shè)計方案是當用戶點擊搜索按鈕后,用戶界面需要重新刷新列出相關(guān)聯(lián)的數(shù)據(jù)。
如果列表過長,數(shù)據(jù)過多,UI“卡頓”,即渲染對用戶可見。這種卡頓也會大大降低產(chǎn)品性能。開發(fā)人員可以使用一些技術(shù),如節(jié)流和防抖,這些技術(shù)會有一定幫助,但不是完美的解決方案。
節(jié)流限制特定函數(shù)被調(diào)用的次數(shù)。使用節(jié)流,我們可以避免重復(fù)調(diào)用昂貴和耗時的API或函數(shù)。這個過程能夠提高性能,尤其是在用戶界面上呈現(xiàn)信息。
防抖會在預(yù)定的時間內(nèi)忽略對函數(shù)的調(diào)用。函數(shù)調(diào)用僅在經(jīng)過預(yù)定時間后進行。
下圖描述了卡頓現(xiàn)象:
在等待非緊急 API 調(diào)用完成時,UI 卡頓,從而阻止呈現(xiàn)用戶界面。解決方案是使用并發(fā)模式進行可中斷渲染。

無中斷渲染
通過可中斷渲染,React.js 在處理和重新渲染列表時不會阻塞 UI。它通過暫?,嵥榈墓ぷ?、更新 DOM 并確保 UI 不會卡頓,使 React.js 更加細化。React 使用用戶輸入并行更新或重繪輸入框。React 使用用戶輸入并重繪輸入框并行執(zhí)行。它還更新內(nèi)存中的列表。React 完成更新后,它會更新 DOM 并在用戶的顯示器上重新呈現(xiàn)列表。本質(zhì)上,無中斷渲染使 React 能夠“多任務(wù)”。此功能提供了更流暢的 UI 體驗。
并發(fā)模式
并發(fā)模式是一組功能,可幫助 React 應(yīng)用程序保持響應(yīng)并平滑地適應(yīng)用戶的設(shè)備和網(wǎng)絡(luò)速度能力。并發(fā)模式將其擁有的任務(wù)劃分為更小的塊。 React 的調(diào)度程序可以挑選并選擇要執(zhí)行的作業(yè)。作業(yè)的調(diào)度取決于它們的優(yōu)先級。通過對任務(wù)進行優(yōu)先級排序,它可以停止瑣碎或不緊急的事情,或者進一步推動它們。 React 始終將用戶界面更新和渲染放在首位。
使用并發(fā)模式,我們可以:
- 控制首次渲染過程
- 優(yōu)先處理渲染過程
- 暫停和恢復(fù)組件的渲染
- 緩存和優(yōu)化組件的運行時渲染
- 隱藏顯示內(nèi)容直到需要展示時
隨著 UI 渲染,并發(fā)模式改進了對傳入數(shù)據(jù)的響應(yīng),懶加載控件,異步處理過程。并發(fā)模式保證了用戶界面始終處于激活狀態(tài),并且持續(xù)在后臺更新數(shù)據(jù),并發(fā)模式也始終使用React 的兩個鉤掛:useTransition 和useDeferredValue
使用useDeferredValue Hook
useDeferredValue Hook 的定義如下:
const deferredValue = useDeferredValue(value, { timeoutMs: <some value> });
此命令設(shè)置值在timeoutMs中設(shè)置的時間后“滯后”。 用戶界面是必須立即更新還是必須等待數(shù)據(jù),該命令使用戶界面保持激活狀態(tài)和響應(yīng)性,該Hook避免了 UI 卡頓,并始終保持用戶界面響應(yīng),以保持獲取數(shù)據(jù)滯后的較小成本。
使用 Transition Hook
useTransition Hook 是React 中主要用于掛起的Hook,假設(shè)這樣的場景下:其中有一個帶有用戶名按鈕的網(wǎng)頁。只需點擊一個按鈕,網(wǎng)頁就會在屏幕上顯示用戶的詳細信息。
假設(shè)用戶首先單擊一個按鈕,然后單擊下一個。屏幕要么變成空白,要么我們在屏幕上看到一個微調(diào)器。如果獲取詳細信息花費的時間太長,用戶界面可能會凍結(jié)。
useTransition 方法返回兩個Hook的值:startTransition 和 isPending。定義的語法如下:
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
startTransition 定義的語法:
<button disabled={isPending}
startTransition(() => {
<fetch Calls>
});
</button>
{isPending? " Loading...": null}
使用 useTransition 鉤子,React.js 繼續(xù)顯示沒有用戶詳細信息的用戶界面,直到用戶詳細信息準備好,但 UI 是響應(yīng)式的。React 優(yōu)先考慮用戶界面,以在并行獲取數(shù)據(jù)時保持響應(yīng)。
為獲取數(shù)據(jù)的Suspense
Suspense 是React與并發(fā)模式一起引入的另一個實驗性功能。Suspense使組件能夠在渲染前等待一段預(yù)定的時間。
Suspense的主要作用是從組件異步讀取數(shù)據(jù),而無需擔心數(shù)據(jù)的來源。Suspense最適合延遲加載的概念。Suspense允許數(shù)據(jù)獲取庫通知React數(shù)據(jù)組件是否可以使用。在必要的組件準備就緒之前,React不會更新 UI。
使用Suspense的好處:
1.數(shù)據(jù)獲取庫和React組件之間的集成
2.控制視覺加載狀態(tài)
3.避免競爭條件
Spinner組件的基本語法如下:
import Spinner from './Spinner';
<Suspense fallback={<Spinner />}>
<SomeComponent />
</Suspense>
Concurrent Mode中使用的Suspense允許耗時的組件在等待數(shù)據(jù)的同時開始渲染。同時顯示占位符。這種組合產(chǎn)生了更流暢的UI體驗。
Suspense 和 懶加載組件
React.lazy是一個新功能,它使React.js能夠延遲加載組件。懶加載意味著僅在需要時才加載組件(檢索和呈現(xiàn)它們的代碼)。他們會優(yōu)先考慮最關(guān)鍵的用戶界面組件。React開發(fā)人員建議將懶加載組件包裝在Suspense組件中。
這樣做可確保組件在渲染時不會出現(xiàn)“不良狀態(tài)”。用戶界面在整個過程中保持響應(yīng),并帶來更流暢的用戶體驗。
啟用并發(fā)模式
要啟用并發(fā)模式,請安裝最新的測試版本。安裝 React 的先決條件是節(jié)點數(shù)據(jù)包管理器 (npm)。要安裝測試版本,請執(zhí)行以下命令:
npm install react@experimental react-dom@experimental
要測試是否設(shè)置了測試版本,請創(chuàng)建一個示例 React 應(yīng)用程序。沒有測試功能的渲染代碼如下:
import * as React from 'react';
import { render } from 'react-dom';
render(<App />, document.getElementById('root'));
并發(fā)模式的,具體代碼如下:
import * as React from 'react';
import { createRoot } from 'react-dom';
createRoot(document.getElementById('root')).render(<App />);
這將為整個應(yīng)用程序啟用并發(fā)模式。React 將渲染調(diào)用分為兩部分:
- 創(chuàng)建根元素
- 使用渲染調(diào)用
目前,React 計劃維護三種模式:
- 傳統(tǒng)模式是向后兼容的傳統(tǒng)或當前模式
- 阻塞模式是并發(fā)模式開發(fā)的中間階段
- 并發(fā)模式
阻塞模式是使用createBlockingRoot 調(diào)用來替換createRoot 調(diào)用,在并發(fā)模式的開發(fā)情況下,阻塞模式為開發(fā)者提供了機會來修復(fù)bug或解決問題。
React 官方文檔中也說明了每種模式支持的功能:

示例應(yīng)用:
本文也創(chuàng)建了一個測試程序來驗證并發(fā)模式和其他模式的用法和效果。本文以像素應(yīng)用為例在150*150的畫布上隨機分布像素并包含一個搜索框,每次用戶點擊搜索框時候,畫布會重新渲染自己。
即使UI 界面無法在并發(fā)模式下渲染,用戶輸入也不會停止更新。像素畫布在處理完成后重新渲染。在傳統(tǒng)模式下,快速鍵入時,UI 會停止,有時會在再次渲染畫布之前停止。用戶輸入也會停止并且不會更新。
構(gòu)建像素應(yīng)用程序的主要文件是 canvas.js。我們還制作了一個輸入框,用戶可以在其中輸入任何內(nèi)容。每次按下一個鍵都會重新渲染像素畫布。
代碼示例:Index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
// Traditional or non-Concurrent Mode react
const rootTraditional = document.getElementById("root");
ReactDOM.render(<App caption="Traditional or Block Rendering" />,
rootTraditional);
// Concurrent Mode enabled
const rootConcurrent = document.getElementById("root-concurrent");
ReactDOM.createRoot(rootConcurrent).render(<App caption="Interruptible
Rendering" />);
App.js
import React, { useState, useDeferredValue } from "react";
import "./App.css";
import { Canvas } from "./Canvas";
export default function App(props)
{ const [value, setValue] = useState("");
//This is available only in the Concurrent mode.
const deferredValue = useDeferredValue(value, {
timeoutMs: 5000
});
const keyPressHandler = e => {
setValue(e.target.value);
};
return (
<div className="App">
<h1>{props.caption}</h1>
<input onKeyUp={keyPressHandler} />
<Canvas value={deferredValue} />
</div>
);
}
Canvas.js
import React from "react";
const CANVAS_SIZE = 70;
const generateRandomColor = () => {
var letters = "0123456789ABCDEF";
var color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
const createCanvas = (rows, columns) => {
let array = [];
for (let i = 0; i < rows; i++) {
let row = [];
for (let j = 0; j < columns; j++) {
row.push(0);
}
array.push(row);
}
return array;
};
//This is the square with the pixels
const drawCanvas = value => {
const canvas = createCanvas(CANVAS_SIZE, CANVAS_SIZE);
return canvas.map((row, rowIndex) => {
let cellsArrJSX = row.map((cell, cellIndex) => {
let key = rowIndex + "-" + cellIndex;
return (
<div
style={{ backgroundColor: generateRandomColor() }}
className="cell"
key={"cell-" + key}
/>
);
});
return (
<div key={"row-" + rowIndex} className="canvas-row">
{cellsArrJSX}
</div>
);
});
};
export const Canvas = ({ value }) => {
return (
<div>
<h2 style={{ minHeight: 30 }}>{value}</h2>
<div className="canvas">{drawCanvas(value)}</div>
</div>
);
};
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<title>React App Concurrent Mode</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="container">
<div id="root" class="column"></div>
<div id="root-concurrent" class="column"></div>
</div>
</body>
</html>
運行示例
讓我們看看我們的代碼。我們看到的第一個屏幕是初始屏幕。使用傳統(tǒng)或塊渲染是現(xiàn)在React 的做法??芍袛噤秩臼遣l(fā)模式的測試功能。我們先看看傳統(tǒng)的渲染工作。

像素畫布在每次擊鍵時重新渲染。在傳統(tǒng)渲染中,整個 UI 會在每次擊鍵時暫停,直到它可以重新渲染屏幕。在此期間,即使我們繼續(xù)打字,用戶輸入不會更新。
下圖顯示可中斷渲染。在可中斷渲染中,用戶可以繼續(xù)輸入。在為每次擊鍵并行重新渲染畫布時,UI 不會停止或停止。

重新渲染完成后,React 會更新 UI。雖然在靜態(tài)截圖中很難看到,但我們可以看到網(wǎng)格在變化,但用戶仍然可以打字而不會出現(xiàn) UI 卡頓的情況。

總結(jié)
在本文中,我們研究了 React 的測試并發(fā)功能和 Suspense。使用并發(fā)模式,React.js 始終保持用戶界面響應(yīng)。它將應(yīng)用程序的任務(wù)分解為更小的塊,并允許對用戶界面任務(wù)進行優(yōu)先級排序。因此,此模式可提供更流暢和無縫的用戶體驗,并提高應(yīng)用程序的整體性能。
結(jié)合并發(fā)模式,Suspense 允許用戶界面保持響應(yīng)。同時,數(shù)據(jù)獲取等繁重耗時的任務(wù)可以并行完成,從而提供整體無縫體驗。
有關(guān)并發(fā)模式的完整詳細信息可在 React 官方文檔中了解。
隨著React版本的改進, React框架越來越被更多的中國前端開發(fā)者所熟知并且廣泛應(yīng)用到他們的項目開發(fā)中。是繼續(xù)Vue.js 后又一備受歡迎的前端主流框架,現(xiàn)在也因此衍生除了很多支持與React框架集成的功能工具, 如前端報表ActiveReportsJS控件,提供了與 React 直接集成的在線編輯器和報表展示工具,完善前端的數(shù)據(jù)展示功能。
到此這篇關(guān)于React 并發(fā)功能體驗-前端的并發(fā)模式已經(jīng)到來的文章就介紹到這了,更多相關(guān)React 并發(fā)功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react數(shù)據(jù)管理機制React.Context源碼解析
這篇文章主要為大家介紹了react數(shù)據(jù)管理機制React.Context源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
React實現(xiàn)文件上傳和斷點續(xù)傳功能的示例代碼
這篇文章主要為大家詳細介紹了React實現(xiàn)文件上傳和斷點續(xù)傳功能的相關(guān)知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習一下2024-02-02
React Antd中如何設(shè)置表單只輸入數(shù)字
這篇文章主要介紹了React Antd中如何設(shè)置表單只輸入數(shù)字問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
詳解使用WebPack搭建React開發(fā)環(huán)境
這篇文章主要介紹了詳解使用WebPack搭建React開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2019-08-08

