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 和错误边界组件可用于处理动态加载组件时发生的意外错误。

广告
© . All rights reserved.