跳到主要內容

關於新架構

自 2018 年以來,React Native 團隊一直在重新設計 React Native 的核心內部結構,以使開發人員能夠創建更高品質的體驗。截至 2024 年,這個版本的 React Native 已在大規模生產環境中獲得驗證,並為 Meta 的生產應用程式提供動力。

術語「新架構」指的是新的框架架構以及將其引入開源的工作。

React Native 0.68 起,新架構已作為實驗性選擇加入功能提供,並在後續的每個版本中持續改進。團隊現在正努力使這成為 React Native 開源生態系統的預設體驗。

為何需要新架構?

經過多年使用 React Native 進行建構,團隊發現了一系列限制,這些限制阻礙開發人員打造具有高度潤飾度的特定體驗。這些限制是框架現有設計的根本問題,因此新架構最初是對 React Native 未來的投資。

新架構解鎖了在傳統架構中不可能實現的功能和改進。

同步佈局和效果

建構自適應 UI 體驗通常需要測量視圖的大小和位置,並調整佈局。

今天,您可以使用 onLayout 事件來取得視圖的佈局資訊並進行任何調整。但是,onLayout 回呼中的狀態更新可能會在繪製先前的渲染之後應用。這表示使用者可能會看到初始佈局渲染和回應佈局測量之間的過渡狀態或視覺跳動。

使用新架構,我們可以透過同步存取佈局資訊和正確排程的更新來完全避免這個問題,如此一來,使用者不會看到任何過渡狀態。

範例:渲染工具提示

測量工具提示並將其放置在視圖上方,讓我們能夠展示同步渲染解鎖的功能。工具提示需要知道其目標視圖的位置,以確定其應渲染的位置。

在目前的架構中,我們使用 onLayout 來取得視圖的測量值,然後根據視圖的位置更新工具提示的定位。

jsx
function ViewWithTooltip() {
// ...

// We get the layout information and pass to ToolTip to position itself
const onLayout = React.useCallback(event => {
targetRef.current?.measureInWindow((x, y, width, height) => {
// This state update is not guaranteed to run in the same commit
// This results in a visual "jump" as the ToolTip repositions itself
setTargetRect({x, y, width, height});
});
}, []);

return (
<>
<View ref={targetRef} onLayout={onLayout}>
<Text>Some content that renders a tooltip above</Text>
</View>
<Tooltip targetRect={targetRect} />
</>
);
}

使用新架構,我們可以利用 useLayoutEffect 在單次提交中同步測量和應用佈局更新,避免視覺「跳動」。

jsx
function ViewWithTooltip() {
// ...

useLayoutEffect(() => {
// The measurement and state update for `targetRect` happens in a single commit
// allowing ToolTip to position itself without intermediate paints
targetRef.current?.measureInWindow((x, y, width, height) => {
setTargetRect({x, y, width, height});
});
}, [setTargetRect]);

return (
<>
<View ref={targetRef}>
<Text>Some content that renders a tooltip above</Text>
</View>
<Tooltip targetRect={targetRect} />
</>
);
}
A view that is moving to the corners of the viewport and center with a tooltip rendered either above or below it. The tooltip is rendered after a short delay after the view moves
工具提示的非同步測量和渲染。請參閱程式碼
A view that is moving to the corners of the viewport and center with a tooltip rendered either above or below it. The view and tooltip move in unison.
工具提示的同步測量和渲染。請參閱程式碼

支援並行渲染器和功能

新架構支援 React 18 及更高版本中提供的並行渲染和功能。您現在可以在 React Native 程式碼中使用 Suspense for data-fetching、Transitions 和其他新的 React API 等功能,進一步統一 Web 和原生 React 開發之間的程式碼庫和概念。

並行渲染器還帶來了開箱即用的改進,例如自動批次處理,這減少了 React 中的重新渲染。

範例:自動批次處理

使用新架構,您將透過 React 18 渲染器獲得自動批次處理。

在此範例中,滑桿指定要渲染的圖塊數量。從 0 拖曳滑桿到 1000 將觸發一系列快速的狀態更新和重新渲染。

在比較 相同程式碼的渲染器時,您可以直觀地注意到渲染器提供更流暢的 UI,且中間 UI 更新較少。來自原生事件處理常式(例如此原生 Slider 組件)的狀態更新現在已批次處理。

A video demonstrating an app rendering many views according to a slider input. The slider value is adjusted from 0 to 1000 and the UI slowly catches up to rendering 1000 views.
使用傳統渲染器渲染頻繁的狀態更新。
A video demonstrating an app rendering many views according to a slider input. The slider value is adjusted from 0 to 1000 and the UI resolves to 1000 views faster than the previous example, without as many intermediate states.
使用 React 18 渲染器渲染頻繁的狀態更新。

新的並行功能,例如 Transitions,讓您能夠表達 UI 更新的優先順序。將更新標記為較低優先順序會告訴 React,它可以「中斷」渲染更新以處理較高優先順序的更新,從而確保在重要的地方提供反應靈敏的使用者體驗。

範例:使用 startTransition

我們可以基於先前的範例,展示轉換如何中斷正在進行的渲染以處理較新的狀態更新。

我們使用 startTransition 包裝圖塊編號狀態更新,以指示渲染圖塊可以中斷。startTransition 還提供一個 isPending 標誌,以告知我們轉換何時完成。

jsx
function TileSlider({value, onValueChange}) {
const [isPending, startTransition] = useTransition();

return (
<>
<View>
<Text>
Render {value} Tiles
</Text>
<ActivityIndicator animating={isPending} />
</View>
<Slider
value={1}
minimumValue={1}
maximumValue={1000}
step={1}
onValueChange={newValue => {
startTransition(() => {
onValueChange(newValue);
});
}}
/>
</>
);
}

function ManyTiles() {
const [value, setValue] = useState(1);
const tiles = generateTileViews(value);
return (
<TileSlider onValueChange={setValue} value={value} />
<View>
{tiles}
</View>
)
}

您會注意到,在轉換中的頻繁更新下,React 渲染的中間狀態較少,因為它會在狀態過時後立即跳出渲染狀態。相比之下,在沒有轉換的情況下,會渲染更多中間狀態。這兩個範例仍然使用自動批次處理。儘管如此,轉換為開發人員提供了更大的能力來批次處理正在進行的渲染。

A video demonstrating an app rendering many views (tiles) according to a slider input. The views are rendered in batches as the slider is quickly adjusted from 0 to 1000. There are less batch renders in comparison to the next video.
渲染帶有轉換的圖塊以中斷過時狀態的正在進行的渲染。請參閱程式碼
A video demonstrating an app rendering many views (tiles) according to a slider input. The views are rendered in batches as the slider is quickly adjusted from 0 to 1000.
渲染圖塊而不將其標記為轉換。請參閱程式碼

快速 JavaScript/原生介面

新架構移除了 JavaScript 和原生之間的非同步橋接器,並以 JavaScript 介面 (JSI) 取代。JSI 是一種介面,允許 JavaScript 持有對 C++ 物件的參考,反之亦然。透過記憶體參考,您可以直接調用方法,而無需序列化成本。

JSI 啟用了 VisionCamera,這是一個流行的 React Native 相機函式庫,可即時處理幀。典型的幀緩衝區為 10 MB,這相當於每秒約 1 GB 的資料,具體取決於幀速率。與橋接器的序列化成本相比,JSI 可以輕鬆處理如此大量的介面資料。JSI 可以公開其他基於複雜實例的類型,例如資料庫、影像、音訊樣本等。

在新架構中採用 JSI 從所有原生-JavaScript 互操作中移除了此類序列化工作。這包括初始化和重新渲染原生核心組件,例如 ViewText。您可以閱讀更多關於我們在新架構中渲染效能調查以及我們測得的改進基準。

啟用新架構後,我可以期待什麼?

雖然新架構啟用了這些功能和改進,但為您的應用程式或函式庫啟用新架構可能不會立即改善效能或使用者體驗。

例如,您的程式碼可能需要重構才能利用同步佈局效果或並行功能等新功能。雖然 JSI 將最大限度地減少 JavaScript 和原生記憶體之間的開銷,但資料序列化可能不是您應用程式效能的瓶頸。

在您的應用程式或函式庫中啟用新架構是選擇加入 React Native 的未來。

團隊正在積極研究和開發新架構解鎖的新功能。例如,Web 對齊是 Meta 正在積極探索的一個領域,它將發佈到 React Native 開源生態系統。

您可以追蹤並在我們的專用討論與提案儲存庫中做出貢獻。

我今天應該使用新架構嗎?

在 0.76 版本中,新架構在所有 React Native 專案中預設啟用。

如果您發現任何運作不佳的地方,請使用此範本開啟一個 issue。

如果由於任何原因您無法使用新架構,您仍然可以選擇退出

Android

  1. 開啟 android/gradle.properties 檔案
  2. newArchEnabled 標誌從 true 切換為 false
gradle.properties
# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
-newArchEnabled=true
+newArchEnabled=false

iOS

  1. 開啟 ios/Podfile 檔案
  2. 在 Podfile 的主要範圍中新增 ENV['RCT_NEW_ARCH_ENABLED'] = '0'範本中的參考 Podfile
diff
+ ENV['RCT_NEW_ARCH_ENABLED'] = '0'
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
  1. 使用以下命令安裝您的 CocoaPods 相依性
shell
bundle exec pod install