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 Lazy 组件

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 组件包含一个回退 props 来指定回退 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() 功能加载
  • 由于所有路由(Home 和 About )都是通过动态导入加载的,因此每个路由在其初始化过程中将仅加载必要的组件,而不是所有组件。

React.lazy() 仅支持默认导出。在 React 中,我们可以通过指定动态名称而不是默认关键字来导出组件,如下所示 -


 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 (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 属性来渲染具有给定名称的你好消息。

接下来,创建一个简单的组件 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() 加载 你好 组件,如下图所示 -


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 包中导入了 lazy 和 Suspense 组件。
  • 通过使用 Suspense SimpleErrorBoundary 组件包装它来使用 Hello 组件。

最后,在浏览器中打开应用程序并检查最终结果。延迟负载在前端没有任何可见的变化。它将以通常的方式呈现你好组件,如下所示 -

Applying Lazy Loading

总结

代码吐槽将有助于优化大型应用程序,只需加载特定页面中使用的必要组件。Suspense and error boundary component 可用于在动态加载组件时处理意外错误。