在 React Native 中原生實現動態匯入

發表於2024-02-21

image.png

在React Native社群中,原生動態匯入一直是期待已久的功能。在React Native 0.72 版本釋出之前,只能透過第三方庫和其他變通方法實現動態匯入,例如使用 React.lazy()Suspense 函式。現在,動態匯入已經成為React Native框架的原生部分。

在這篇文章中,我們將比較靜態和動態匯入,學習如何原生地處理動態匯入,以及有效實施的最佳實踐。

靜態匯入 vs. 動態匯入

在深入研究實現細節之前,理解什麼是動態匯入以及它們與靜態匯入有何不同是至關重要的,靜態匯入是在JavaScript中包含模組的更常見方式。

靜態匯入是你在檔案頂部使用 importrequire 語法宣告的匯入。這是因為在應用程式啟動時,它們可能需要在你的整個應用程式中可用。

這是一個例子:

import React from 'react';
import {View, Text} from 'react-native';
const MyComponent = require('./MyComponent');

靜態匯入是同步的,意味著它們會阻塞主執行緒,直到模組完全載入。這種行為可能導致應用程式啟動時間變慢,特別是在較大的應用程式中。然而,當一個庫或模組在程式碼庫的多個時間或多個地方需要時,靜態匯入就會顯得非常有用。

相比之下,動態匯入賦予開發者在需要時即時匯入模組的能力,引領了一個非同步正規化。這意味著程式碼是按需載入的。

總的來說,靜態匯入和動態匯入的主要區別在於,靜態匯入在編譯時解析,而動態匯入在執行時解析。

在 React Native v0.72 版本之前,動態匯入並不是開箱即用的支援,因為它們與 Metro 打包器不相容,Metro 打包器負責在 React Native 應用程式中打包 JavaScript 程式碼和資產。

Metro 打包器不允許任何執行時更改,並透過移除未使用的模組並用靜態引用替換它們來最佳化包大小。這意味著 React Native 開發者必須依賴第三方庫或自定義解決方案來在他們的應用中實現動態匯入。我們將在本文後面探討這些。

如何在React Native中原生實現動態匯入

要在 React Native中 使用原生動態匯入,你需要安裝0.72或更高版本的React Native。你可以透過在終端執行 npx react-native --version 來檢查你的React Native版本。你還需要在你的專案中配置0.66或更高版本的Metro打包器。

React Native 中使用原生動態匯入有兩種方式:使用 import() 語法或使用 require.context() 方法。

使用 import() 語法

根據Metro Bundler官方文件:

import() 呼叫在開箱即用的情況下得到支援。在React Native中,使用 import() 會自動分割你的應用程式程式碼,使其在開發過程中載入速度更快,而不影響釋出構建。

import() 語法與靜態 import 關鍵字相似,但你可以在程式碼的任何地方使用它,只要你處理好 promise 的解決和拒絕。

例如,假設你有一個名為 SomeComponent 的元件,你希望根據某些條件動態載入它。你可以像這樣使用 import() 語法:

const loadSomeComponent = async () => {
  try {
    const SomeComponent = await import('./SomeComponent');
    // Do something with SomeComponent
  } catch (error) {
    // Handle error
  }
};

// Use SomeComponent conditionally
if (someCondition) {
  loadSomeComponent();
}

注意:你需要在 async 函式內使用 await 關鍵字來等待promise 的解決。或者,你可以使用 .then().catch() 方法來處理 promise 的解決和拒絕。

使用 require.context() 方法

require.context() 方法現在是 Metro 打包器的一個支援特性,允許你為動態匯入建立一個上下文。這個特性是由 Evan Bacon 新增到Metro庫中的。

context 是一個包含與給定模式匹配的一組模組或元件資訊的物件。你可以使用 require.context() 方法來建立這樣的上下文:

// Create a context for all components in the ./components folder
const context = require.context('./components', true);

require.context() 方法的第一個引數是你想要查詢模組或元件的基礎目錄。第二個引數是一個布林值,表示你是否想要包含子目錄。

有了 require.context ,你現在可以根據變數或正規表示式進行匯入。

這是一個示例,展示瞭如何使用 require.context 從資料夾中匯入所有圖片並將它們顯示在列表中:

// App.js
import React from 'react';
import {FlatList, Image, StyleSheet} from 'react-native';

// Import all the images from the assets/images folder
const images = require.context('./assets/images', true, /\.png$/);

// Create an array of image sources
const imageSources = images.keys().map((key) => images(key));

const App = () => {
  // Render each image in a flat list
  return (
    <FlatList
      data={imageSources}
      keyExtractor={(item) => item}
      renderItem={({item}) => <Image style={styles.image} source={item} />}
    />
  );
};

const styles = StyleSheet.create({
  image: {
    width: 100,
    height: 100,
    margin: 10,
  },
});

export default App;

React Native v0.72引入了透過 require.context 方法支援動態匯入,這與webpack提供的方式類似。

但是 require.context 一直以來都被Expo路由器在後臺使用,以根據檔案目錄結構和你擁有的檔案自動建立路由。它使用一個帶有正規表示式的 require.context 呼叫,所有的路由都可以在執行時被確定。

例如,如果你有一個名為 app/home.tsx 的檔案,它將變成一條路徑為 /home 的路由。如果你有一個名為 app/profile/settings.tsx 的檔案,它將變成一條路徑為 /profile/settings 的路由。

例如,如果你有一個名為 app/home.tsx 的檔案,它將成為一個路徑為 /home 的路由。如果你有一個名為 app/profile/settings.tsx 的檔案,它將成為一個路徑為 /profile/settings 的路由。

因此,你無需手動定義或匯入你的路由——Expo Router會為你完成!

實現動態匯入的第三方解決方案

使用 React.lazy() 和 Suspense

React.lazy()Suspense 是React的特性,允許你懶載入元件,也就是說,只有當它們被渲染時才會載入。你可以使用 React.lazy() 函式來建立一個包裝動態匯入的元件,你可以使用 Suspense 來顯示一個備用元件,而動態匯入正在載入。

這是一個例子:

import React, { lazy, Suspense } from "react";
import { Text, View } from "react-native";
import { styles } from "./styles";

const DynamicComponent = lazy(() => import("./DynamicComponent"));

function App() {
  return (
    <View style={styles.container}>
      <Suspense fallback={() => <Text>Loading ....</Text>}>
        <DynamicComponent />
      </Suspense>
    </View>
  );
}
export default App;

在你的React Native應用程式中,使用 React.lazy()Suspense 是實現動態匯入的好方法。然而,需要注意的是 React.lazy() 是專門為 React 元件的程式碼分割設計的。如果你需要動態匯入非元件的 JavaScript 模組,你可能需要考慮其他方法。

可載入元件

Loadable Components是一種將你的React Native程式碼分割成可以按需載入的小塊的方法。在React Native中,你可以使用react-loadable庫來動態載入和渲染元件。

import Loadable from 'react-loadable';

// Define a loading component while the target component is being loaded
const LoadingComponent = () => <ActivityIndicator size="large" color="#0000ff" />;

// Create a dynamic loader for the target component
const DynamicComponent = Loadable({
  loader: () => import('./YourComponent'), // Specify the target component path
  loading: LoadingComponent, // Use the loading component while loading
});

// Use the dynamic component in your application
function App() {
  return (
    <View>
      <DynamicComponent />
    </View>
  );
}

在這段程式碼中:

  • react-loadable 庫中匯入 Loadable 函式
  • 定義一個載入元件(例如,一個 ActivityIndicator ),在目標元件載入時將會顯示。
  • 使用 Loadable 函式建立一個動態元件。為 loader 屬性提供一個匯入目標元件的函式(將 './YourComponent' 替換為元件的實際路徑),並指定 loading 屬性以在載入過程中顯示載入元件。
  • 最後,在你的應用的使用者介面中使用 DynamicComponent 。它將動態載入目標元件,並在準備就緒後顯示它,同時顯示載入元件。

這個庫最初是為React網頁應用設計的,所以它可能並不總是在React Native中執行得很好。

React Native中動態匯入的好處

動態匯入為開發者提供了幾個優勢:

  • 更快的啟動時間:透過只按需載入所需的程式碼,動態匯入可以顯著減少你的應用啟動所需的時間。這對於提供流暢的使用者體驗至關重要,尤其是在裝置或網路較慢的情況下。
  • 提高程式碼可維護性:動態匯入可以透過讓你將不常用的元件或庫分離到單獨的模組中,更有效地組織你的程式碼庫。這可以提高程式碼的可維護性,使得在你的應用的特定部分工作變得更容易。
  • 漸進式載入:動態匯入支援漸進式載入。你可以優先載入關鍵元件,而不是強迫使用者等待整個應用程式的載入,同時在後臺載入次要功能。這確保了使用者的初始體驗無縫,同時你的應用程式的不太重要的部分在後臺載入,保持使用者的參與度。
  • 最佳化的包:動態匯入允許你透過將它們分割成更小、更易管理的塊來最佳化你的JavaScript包。這可以導致包大小的減小,從而減少應用程式的記憶體佔用並加速載入過程。

使用動態匯入的最佳實踐

  • 謹慎使用動態匯入:動態匯入並非能解決你所有效能和使用者體驗問題的靈丹妙藥。它們帶來了一些權衡,如增加的複雜性,潛在的錯誤,以及對網路連線的依賴。因此,你應該只在必要時使用它們,而不是過度使用它們。
  • 使用載入指示器和佔位符:載入指示器可以向使用者顯示應用正在動態載入一些模組以及需要多長時間。佔位符可以向使用者展示當模組載入完成後應用會是什麼樣子,並防止佈局變動或空白空間。你可以使用像 ActivityIndicator 或 Skeleton 這樣的React Native內建元件,或者像 react-native-loading-spinner-overlay react-native-skeleton-placeholder 這樣的第三方庫來實現這個目的。
  • 使用錯誤邊界和回退:在使用動態匯入時,你應該使用錯誤邊界和回退來處理錯誤和失敗。錯誤邊界是可以捕獲並處理其子元件中的錯誤的元件。回退是在原始元件無法載入或渲染時可以渲染的元件。你可以使用像React中的 ErrorBoundary 這樣的內建元件,或者像 react-error-boundaryreact-native-error-boundary 這樣的第三方庫來實現這個目的。

總結

在這篇文章中,我們學習瞭如何在React Native中使用原生動態匯入。有了動態匯入這個強大的工具,你可以使你的React Native應用更高效、響應更快、使用者體驗更友好。謹慎使用動態匯入並遵循最佳實踐以確保無縫的使用者體驗是至關重要的。

相關文章