React中代码分割的4种实现方式

目录
  • 前言
  • import()
  • React.lazy
  • import() + React Loadable
  • UmiJS 按需加载
  • 总结

前言

在 React 应用中,我们通常的做法是直接将某个模块导入到页面中,这样做导致的结果是打包出来的包体积过大。尤其是在引入了体积巨大的第三个库的情况下,打包后的包体积会十分巨大。因此,我们需要关注我们的应用中所包含的代码,以避免因体积过大而导致加载时间过长。

对代码进行分割能够“懒加载”当前用户所需要的内容,能够显著提高应用的性能。尽管并没有减少应用的整体代码体积,但可以避免加载用户永远不需要的代码,并在初始加载的时候可以减少所需加载的代码量。

下面,我们分别来介绍下在 React 中实现代码分割的几种方式。

import()

import() 是 Webpack 提供的用于分割代码的一个方法。该方法的返回结果是Promise,当文件加载完成后悔将模块导出给 promise.then 方法的回调。

例如有一个 math 模块,导出了 add方法和 minus 方法:

export const add = (a, b) => {
	return a + b;
}

export const minus = (a, b) => {
	return a - b;
}

通常的做法是在页面直接引入模块:

import { add } from './math'

console.log(add(5, 10));

使用 import 动态导入模块:

import('./math').then((math) => {
	console.log(math.add(5, 10))
})

当 Webpack 解析到该语法时,会自动进行代码分割。如果是使用 Create React App 创建的 React 应用,import 功能已开箱即用。

import React, { Component } from 'react';

class App extends Component {
  handleClick = () => {
    import('./math')
      .then(({ add }) => {
        add(5, 10)
      })
      .catch(err => {
        // Handle failure
      });
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>两数相加</button>
      </div>
    );
  }
}

export default App;

React.lazy

React.lazy 方法可以让我们动态加载组件,有助于缩减打包后 bundle 的体积,并延迟加载在初次渲染时未用到的组件。

React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 export default 的 React 组件。

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

React.lazy 返回的是一个异步组件 不能单独使用,需要配合 React.Suspense 使用。当这个异步组件的状态是 pending 时显示的是 Suspense 中 fallback 的内容,只有 resolve 时才会显示加载好的组件。如此使得我们可以在使用 lazy 组件时做优雅降级(如在 fallback添加 loading 效果等)。

import React, { Suspense } from 'react';

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

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

import() + React Loadable

React Loadable 是一个轻量级的代码分割组件,它是一个高阶组件,能让你的应用程序在渲染之前动态的加载任何模块。

使用 import() + React Loadable ,能优雅的实现基于 react-router 4.x 版本的路由分割:

import Loadable from 'react-loadable';

const LoadableBar = Loadable({
  loader: () => import('./components/Bar'),
  loading() {
    return <div>Loading...</div>
  }
});

class MyComponent extends React.Component {
  render() {
    return <LoadableBar/>;
  }
}

在实际业务开发中,我们通常会使用一些框架来快速开发React应用。在这些框架中,通常都会提供按需加载的功能。下面,我们来看看 UmiJS 框架中的按需加载。

UmiJS 按需加载

UmiJS 是一个可扩展的企业级前端应用框架,它以路由为基础,支持配置式路由和约定式路由。UmiJS 封装了一个 dynamic 组件来实现代码分割。

启用按需加载

UmiJS 的按需加载功能默认是关闭的,需要在使用之前通过配置开启。在 UmiJS 项目中添加如下的配置开启:

export default {
  dynamicImport: {},
}

使用按需加载

首先封装一个异步组件:

import { dynamic } from 'umi';
export default dynamic({
  loader: async function() {
    // 这里的注释 webpackChunkName 可以指导 webpack 将该组件 HugeA 以这个名字单独拆出去
    const { default: HugeA } = await import(/* webpackChunkName: "external_A" */ './HugeA');
    return HugeA;
  },
});

然后使用封装好的异步组件:

import React from 'react';
import AsyncHugeA from './AsyncHugeA';

export default () => {
  return <AsyncHugeA />;
}

总结

到此这篇关于React中代码分割的文章就介绍到这了,更多相关React代码分割内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Webpack3+React16代码分割的实现

    项目背景 最近项目里有个webpack版本较老的项目,由于升级和换框架暂时不被leader层接受o(╥﹏╥)o,只能在现有条件进行优化. webpack3 + react16 webpack v3配置检查 很明显项目的配置是从v1继承过来的,v1->v3的升级较为简单,参考官网https://webpack.js.org/migrate/3/即可. loaders变为rules 不再支持链式写法的loader,json-loader不需要配置 UglifyJsPlugin插件需要自己开启mini

  • react 实现页面代码分割、按需加载的方法

    虽然一直有做 react 相关的优化,按需加载.dll 分离.服务端渲染,但是从来没有从路由代码分割这一块入手过,昨天在本地开发时没有测试成功,今天又搞了下,已经部署到线上环境了,今天就这个记录一下. 修改配置 开发环境:webpack@v3 .react-router@v4 安装依赖: $ yarn add babel-plugin-syntax-dynamic-import -dev 修改 .babelrc 文件:在 plugins 中添加 "syntax-dynamic-import&qu

  • React中代码分割的4种实现方式

    目录 前言 import() React.lazy import() + React Loadable UmiJS 按需加载 总结 前言 在 React 应用中,我们通常的做法是直接将某个模块导入到页面中,这样做导致的结果是打包出来的包体积过大.尤其是在引入了体积巨大的第三个库的情况下,打包后的包体积会十分巨大.因此,我们需要关注我们的应用中所包含的代码,以避免因体积过大而导致加载时间过长. 对代码进行分割能够“懒加载”当前用户所需要的内容,能够显著提高应用的性能.尽管并没有减少应用的整体代码体

  • React 中使用 Redux 的 4 种写法小结

    目录 不使用 Redux 的写法 最底层的写法 React-Redux React-Redux 配合 connect 高阶组件 React-Rudex 配合 React Hooks Redux Toolkit 总结 Redux 是一种状态容器 JS 库,提供可预测的状态管理,经常和 React 配合来管理应用的全局状态,进行响应式组件更新. Redux 一般来说并不是必须的,只有在项目比较复杂的时候,比如多个分散在不同地方的组件使用同一个状态.对于这种情况,如果通过 props 层层传递,代码会

  • Java中枚举类型的一种使用方式

    今天改同事的代码发现同事的代码中有大量的if else语句.很不美观而且可读性太差. 因为需要给前端一个key,value的列表.这个列表写死.然而同事的代码. 放几张图,大家自己感受.我都不知道以后这个api咋维护,新增一个工站,减少一个工站. 果然新的任务新增4个工站,好吧,开始给代码装扮一下. 首先,写一个枚举类. package com.smartflow.common.enumpackage; /** * @author :tao * @date :Created in 2020/8/

  • java中实现分页的几种常见方式总结

    目录 1. 前言 2. 先说结论 3. 例子 1. 数据库SQL的限制条件(limit.fetch) 2. 使用List集合的截取功能实现 3. 插件PageHelper 总结 1. 前言 无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下. 2. 先说结论 分页功能直接交给前端实现(根据业务场景且仅仅只能用于数据量少的情况).即后端不做任何数据的限制,直接把全部数据返回给前端,前端通过组件实现分页,筛选等功能.请不要轻视该方式,好处即只需要前后端交

  • 一文详解Python中实现单例模式的几种常见方式

    目录 Python 中实现单例模式的几种常见方式 元类(Metaclass): 装饰器(Decorator): 模块(Module): new 方法: Python 中实现单例模式的几种常见方式 元类(Metaclass): class SingletonType(type): """ 单例元类.用于将普通类转换为单例类. """ _instances = {} # 存储单例实例的字典 def __call__(cls, *args, **kwa

  • oracle中if/else的三种实现方式详解

    1.标准sql规范 1.单个IF IF v=... THEN END IF; 2.IF ... ELSE IF v=... THEN ELSE t....; END IF; 3.多个IF IF v=... THEN ELSIF v=... THEN t...; END IFL 注意: 多个IF的是'ELSIF' 不是 ' ELSE IF' 2.decode函数 DECODE(VALUE,IF1,THEN1,IF2,THEN2,IF2,THEN2,..,ELSE) 表示如果value等于if1时,

  • React中获取数据的3种方法及优缺点

    为了保证的可读性,本文采用意译而非直译. 在执行 I/O 操作(例如数据提取)时,要先发送网络请求,然后等待响应,接着将响应数据保存到组件的状态,最后进行渲染. 在 React 中生命周期方法.Hooks和 Suspense是获取数据的方法.接下用事例演示一下如何使用它们并说明每种方法的优点和缺点,以便咱们更好的编写异步操作代码. 1.使用生命周期方法请求数据 应用程序Employees.org做两件事: 1.一进入程序就获取20名员工. 2.可以通过过滤条件来筛选员工. 在实现这两个需求之前,

  • 关于react中组件通信的几种方式详解

    前言 刚入门React可能会因为React的单向数据流的特性而遇到组件间沟通的麻烦,下面这篇文章就来给大家详细介绍下,在开始之前先来看一张图: react组件通信 需要组件之进行通信的几种情况 父组件向子组件通信 子组件向父组件通信 跨级组件通信 没有嵌套关系组件之间的通信 1. 父组件向子组件通信 React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过props向子组件传递需要的信息 Child.jsx import React from 'react'; import Pro

  • React中this丢失的四种解决方法

    发现问题 我们在给一个dom元素绑定方法的时候,例如: <input type="text" ref="myinput" accept = "image/*" onChange = {this.selectFile} /> React组件中不能获取refs的值,页面报错提示:Uncaught TypeError: Cannot read property 'refs' of null or undefind 小栗子 import Re

  • JavaScript中的函数的两种定义方式和函数变量赋值

    复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript"> /*I总结: 1.函数名可以做变量使用,可以赋值,可以传值 2.函数名当参数,传递给另一个函数 */ //===========

随机推荐