React高级指引:代码分割

21 篇文章 0 订阅
21 篇文章 1 订阅

上一节:无障碍
下一节:Context

打包

大多数React应用都会使用WebpackRollupBrowserify来打包代码文件。打包是一个引入文件并把它们合并到一个文件的过程,最终形成一个bundle。这个bundle可以在网页上被加载一整个应用。

例子
App:

// app.js
import { add } from './math.js';

console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
  return a + b;
}

Bundle:

function add(a, b) {
  return a + b;
}

console.log(add(16, 26)); // 42

注意:
你打包的bundle最终与上面的例子有很大的不同。

如果你使用Create React AppNext,jsGatsby或其他类似的工具,那么你可以使用内置的Webpack来打包你的应用。

如果不是,那么你需要自行安装打包工具。比如你可以在Webpack网站查看安装使用教程。

代码分割

打包是个非常棒的技术,但是当你的应用逐渐扩大时,你最终生成的代码包也会随之变大,尤其是当你使用了庞大的第三方库时。为了避免你的应用需要长时间地加载,请时刻注意需要包含在代码包内的代码,以免它变得很大。

为了避免生成体积巨大的代码包,我们需要一开始就分割它们。代码分割是WebpackRollup和Browserify(通过factor-bundle)这类打包器支持的特性,它们可以构建多个代码包并在运行时动态地加载它们。

代码分割你的应用可以让你“懒加载”当前用户需要的部分,使你的应用性能大幅度提高。在没有减少代码量的前提下,你可以避免加载用户不会用到的代码,减少初始化时加载的代码量。

import()

在应用中引进代码分割的最好方式是通过动态import()语法。

之前

import { add } from './math';

console.log(add(16, 26));

之后

import("./math").then(math => {
  console.log(math.add(16, 26));
});

注意:
动态import()语法只是ECMAScript (JavaScript) 的提案,目前还不是标准语法。但是在最近的版本中它将会被引进。

当Webpack在打包时遇到了此类语法,它就会自动地进行代码分割。如果你使用的是Create React App,创建的工程已经为你配置好相关功能,可以直接使用该特性Next,js也支持该特性不需要再进行配置。

如果你自行配置Webpack,那么你可能需要查阅Webpack代码分割指导。你的Webpack配置应该类似这种

如果使用Babel,你需要确保Babel能够解析动态import语法而不是转换它。可以通过babel-plugin-syntax-dynamic-import.了解相关知识。

React.lazy

注意:
React.lazy和Suspense技术目前还不支持服务端渲染。如果你想要对在服务端渲染的应用进行代码分割,我们推荐使用Loadable Components。它有一个很棒的服务端渲染打包指南

React.lazy功能让你把动态import作为常规组件渲染。

之前

import OtherComponent from './OtherComponent';

之后

const OtherComponent = React.lazy(() => import('./OtherComponent'));

OtherComponent组件第一次被渲染时,包含这个组件的代码包会被自动加载。

React.lazy接收一个函数作为参数,这个函数调用动态import()。他必须返回一个Promise对象resolve包含了React组件的default export模块。

这个懒加载组件之后应该在Suspense组件中渲染,这个组件能够在我们等待懒加载组件加载时展示一些后备内容(如加载图标)

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

fallback属性接收任何你想要在等待组件加载时渲染的React元素。你可以把Suspense组件放在懒加载组件层级之上的任意位置。你也可以把多个懒加载组件作为Suspense组件的子元素。

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}

异常捕获边界(Error boundaries)

如果模块加载失败(比如因为网络请求失败导致),这会导致错误。你可以通过异常捕获边界来处理和修复这些异常来给用户一个良好的用户体验。一旦创建了异常捕获边界,你就可以在发生网络异常时通过在懒加载组件层级之上使用它来展示错误状态。

import MyErrorBoundary from './MyErrorBoundary';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

基于路由的代码分割

在哪里引入代码分割是一个让人头疼的事情。你首先要确保你选择的地方能够均匀地分割代码包,此外还要保证这样做不会影响用户体验。

一个好的选择是在路由中使用它。大部分人都习惯在网页跳转时加载切换过程。所以你可以在这个时候需要重新渲染整个页面,这样用户就不用再切换页面的同时再与其他元素交互了。

下面的例子讲述了如何使用React RouterReact.lazy来进行基于路由的代码分割。

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
      </Switch>
    </Suspense>
  </Router>
);

命名导出(Named Exports)

React.lazy目前只支持default export。如果你想要引入的模块使用的是命名导出,那么你可以创建一个新的模块作为媒介来重新default export。这能保证tree shaking能够继续工作,并且不需要引入无用的组件。

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

上一节:无障碍
下一节:Context

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值