ReactJS - 程式碼分割



打包是前端應用中一個重要的階段。它將所有前端程式碼及其依賴項打包成一個大型包 (bundle.js)。最終包的大小由打包器最佳化。一些流行的打包器包括 webpack、parcel 和 rollup。在大多數情況下,最終的包都可以正常工作。如果最終打包的程式碼很大,則可以指示打包器將程式碼打包成多個專案,而不是單個大塊。

讓我們學習如何提示打包器分割程式碼並分別打包它。

動態匯入

動態匯入指示打包器分割程式碼。動態匯入基本上是根據需要獲取所需的模組。正常的程式碼如下所示:

import { round } from './math';
console.log(round(67.78));

相同的程式碼可以動態匯入,如下所示:

import("./math").then(math => {
  console.log(math.round(67.78);
});

React 惰性元件

React 提供了一個函式 React.lazy 來動態匯入元件。通常,我們知道,React 元件的匯入方式如下所示:

import MyComponent from './MyComponent';

要使用 React.lazy() 函式動態匯入上述元件,如下所示:

const MyComponent = React.lazy(() => import('./MyComponent'));
The imported component should be wrapped into a Suspense component to use it in the application.
import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
function App() {
   return (
      <div>
         <Suspense fallback={<div>Loading...</div>}>
            <MyComponent />
         </Suspense>
      </div>
   );
}

Suspense 元件用於在載入原始元件期間載入臨時的 UI。Suspense 元件包含一個 fallback 屬性來指定回退 UI。回退 UI 可以是任何 React 元素。有時,由於網路問題或程式碼錯誤,動態元件可能載入失敗。我們可以使用錯誤邊界來處理這些情況,如下所示:

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';
const MyComponent = React.lazy(() => import('./MyComponent'));
const AnotherComponent = () => (
   <div>
      <MyErrorBoundary>
         <Suspense fallback={<div>Loading...</div>}>
            <section>
               <MyComponent />
            </section>
         </Suspense>
      </MyErrorBoundary>
   </div>
);

這裡:

  • MyErrorBoundary 包裹在 Suspense 元件周圍。

  • 如果載入 MyComponent 時出現任何錯誤,則 MyErrorBoundary 將處理錯誤並回退到其元件中指定的通用 UI。

應用程式碼分割的最佳場景之一是路由。路由可以用來應用程式碼分割,如下所示:

import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
   <BrowserRouter>
      <Suspense fallback={<div>Loading...</div>}>
         <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
         </Routes>
      </Suspense>
   </BrowserRouter>
);

這裡:

  • 所有路由(元件)都使用 React.lazy() 功能載入。

  • 由於所有路由(HomeAbout)都是透過動態匯入載入的,因此每個路由只會在初始化時載入必要的元件,而不是所有元件。

React.lazy() 只支援預設匯出。在 React 中,我們可以透過指定動態名稱而不是 default 關鍵字來匯出元件,如下所示:

export const MyComponent = /* ... */;

為了使其在 React.lazy() 中可用,我們可以使用 default 關鍵字重新匯出元件,如下所示:

export { MyLazyComponent as default } from "./MyComponent.js";

然後,我們可以像往常一樣匯入它:

import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

應用惰性載入

讓我們建立一個新的 React 應用來學習如何在這一節中應用程式碼分割。

首先,使用以下命令建立一個新的 React 應用並啟動它。

create-react-app myapp
cd myapp
npm 

接下來,開啟 App.css (src/App.css) 並刪除所有 CSS 類。

// remove all css classes

接下來,建立一個簡單的 hello 元件,Hello (src/Components/Hello.js),並渲染一條簡單的訊息,如下所示:

import React from "react";
class Hello extends React.Component {
   constructor(props) {
      super(props)
   }
   render() {
      return (
         <div>Hello, {this.props.name}</div>
      );
   }
}
export default Hello;

這裡,我們使用了 name 屬性來使用給定的名稱渲染 hello 訊息。

接下來,建立一個簡單的元件,SimpleErrorBoundary (src/Components/SimpleErrorBoundary.js),並在錯誤期間渲染回退 UI 或子元件,如下所示:

import React from "react";
class SimpleErrorBoundary extends React.Component {
   
   constructor(props) {
      super(props);
      this.state = { hasError: false };
   }
   
   static getDerivedStateFromError(error) {
      return { hasError: true };
   }
   
   componentDidCatch(error, errorInfo) {
      console.log(error);
      console.log(errorInfo);
   }
   
   render() {
      if (this.state.hasError) {
         return <h1>Please contact the administrator.</h1>;
      }
      
      return this.props.children;
   }
}
export default SimpleErrorBoundary;

這裡:

  • hasError 是一個初始化值為 false 的狀態變數。

  • getDerivedStateFromError 在出現錯誤時更新錯誤狀態。

  • componentDidCatch 將錯誤記錄到控制檯。

  • render 將根據應用程式中的錯誤渲染錯誤 UI 或子元件。

接下來,開啟 App 元件 (src/App.js),並透過 React.lazy() 載入 hello 元件,如下所示:

import './App.css'
import React, { Suspense, lazy } from 'react';
import SimpleErrorBoundary from './Components/SimpleErrorBoundary';
const Hello = lazy(() => import('./Components/Hello'));

function App() {
   return (
      <div className="container">
         <div style={{ padding: "10px" }}>
            <div>
               <SimpleErrorBoundary>
                  <Suspense fallback="<div>loading...</div>">
                     <Hello name="Peter" />
                  </Suspense>
               </SimpleErrorBoundary>
            </div>
         </div>
      </div>
   );
}
export default App;

這裡我們:

  • 從 react 包中匯入了 lazySuspense 元件。

  • 使用 Hello 元件,並將其用 Suspense 和 SimpleErrorBoundary 元件包裝。

最後,在瀏覽器中開啟應用程式並檢查最終結果。惰性載入在前端沒有任何可見的變化。它將像下面這樣以通常的方式渲染 hello 元件:

Applying Lazy Loading

總結

程式碼分割有助於透過僅載入特定頁面中使用的必要元件來最佳化大型應用程式。Suspense 和錯誤邊界元件可用於處理動態載入元件時發生的意外錯誤。

廣告