React 异步组件之 Code Splite

发布于 2022-12-05 12:44:13 字数 4207 浏览 102 评论 0

在上一次开发一个大型的SPA网站的时候,因为加载了大量的第三方库,导致 webpack 打包出来的 bundle.js 异常的大,是时候祭出了 code splite 来减少 js 的大小了。所谓的 Code splite 其实就是所谓js的懒加载。因为我们的技术栈使用 react + redux + redux-thunk 配合 create-react-app 来搭建的,所以我们就说说 Create React App 如何来做代码分割。

首先需要申明的是代码分割不是一颗银弹,不要过度优化你的程序除非你的程序到了需要优化的程度,或者想我这样就是想瞎折腾学习学习。如果在开发React过程中发现打包出来的bundle.js越来越大,多半是和我们一样引入了很多组件导致程序在第一次加载的过慢。

思考以下如下的场景:在用户使用一个比较大的程序,当用户只是在登录界面,没有必要将整个程序都加载出来。Create React App起始已经内置了代码分割功能来动态加载 import。Import来动态加载组件通常配合React Router。我们通过设置React Router来根据Url路径来做到按需加载组件。

JS 的模块化规范

代码分割其实加载的一个模块,require/export出生在野生规范,被广泛使用在CommonJS、AMD、CMD等等, import/export则是名门正派由ECMAScript版本进来。

本质的差别:

  • CommonJS 还是 ES6 Module 输出都可以看成是一个具备多个属性或者方法的对象
  • default 是 ES6 Module 所独有的关键字,export default fs 输出默认的接口对象
  • ES6 module 中导入模块的属性或者方法是强绑定,包括基础类型,而 CommonJS 则是普通的值传递或者引用传递。

Async Component

首先我们创建一个包装的 Async Component。

import React, {Component} from'react';

exportdefaultfunctionasyncComponent(importComponent) {
  classAsyncComponentextendsComponent{
    constructor(props) {
      super(props);

      this.setState(component : null)
    }

    async componentDidMount() {
      const {default: component} = await importComponent();

      this.setState({component: component})
    }

    render() {
      const C = tis.state.component;

      return C
        ? <C {...this.props}/>
        : null
    }
  }
  return AsyncComponent;
}

之前我们都是静态的加载组件

import Home from'./containers/Home';

现在我们使用 asyncComponent 来动态加载我们需要的组件

const AsyncHome = asyncComponent(() =>import ('./container/Home'))

比较两者的区别,我们会发现在动态加载起始我们只是包装了一个函数,将一个函数传入,当包装的函数加载完成后在生命周期的componentDidMount()来import我们真正需要的组件。

然后我们来看看将组件使用在 routes,之前我们是直接加载的静态组件

<Route path = '/' exact component = {Home}/>
// <Route path = '/' exact component = {AsyncHome}/>

总结

import React from"react";
import { Route, Switch } from"react-router-dom";
import asyncComponent from"./components/AsyncComponent";
import AppliedRoute from"./components/AppliedRoute";
import AuthenticatedRoute from"./components/AuthenticatedRoute";
import UnauthenticatedRoute from"./components/UnauthenticatedRoute";

const AsyncHome = asyncComponent(() =>import("./containers/Home"));
const AsyncLogin = asyncComponent(() =>import("./containers/Login"));
const AsyncNotes = asyncComponent(() =>import("./containers/Notes"));
const AsyncSignup = asyncComponent(() =>import("./containers/Signup"));
const AsyncNewNote = asyncComponent(() =>import("./containers/NewNote"));
const AsyncNotFound = asyncComponent(() =>import("./containers/NotFound"));

exportdefault ({ childProps }) =>
  <Switch>
    <AppliedRoute
      path="/"
      exact
      component={AsyncHome}
      props={childProps}
    />
    <UnauthenticatedRoute
      path="/login"
      exact
      component={AsyncLogin}
      props={childProps}
    />
    <UnauthenticatedRoute
      path="/signup"
      exact
      component={AsyncSignup}
      props={childProps}
    />
    <AuthenticatedRoute
      path="/notes/new"
      exact
      component={AsyncNewNote}
      props={childProps}
    />
    <AuthenticatedRoute
      path="/notes/:id"
      exact
      component={AsyncNotes}
      props={childProps}
    />
    {/* Finally, catch all unmatched routes */}
    <Route component={AsyncNotFound} />
  </Switch>

通过运行 npm run build 我们会看到 代码切割的 js 分别是 build/static.js/1.chunk.js 之类的,说明我们已经已经完成了代码切割。

react-loadable

如果你讲上面的 asyncComponent 放入了线上环境很有可能会被主管打死,因为上面的代码仅供参考,因为是异步加载所以有很多异常的 corner case 没有考虑在其中。其实已经有大神给我们写好的 react-loadable,使用起来相当方便,再次我也不在赘述了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

荒路情人

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文