dljia
  • 前言
  • es6
    • promise
    • 箭头函数
  • http相关
    • ajax请求中contentType和dataType
    • async和defer的区别
    • cookie、session和token
    • http协议介绍
    • http缓存
    • 转发和重定向
  • js
    • 1-js深浅复制
    • 10-节流防抖
    • 11-Promise常见手写
    • 2-js函数值传递
    • 3-js原型链详解
    • 4-js基础讲解this篇
    • 5-call、apply和bind
    • 6-js中的继承
    • 7-闭包与立即执行函数
    • 8-js事件循环
    • 9-js模块化
  • react
    • React-diff
    • React-fiber
    • React组件设计规则
    • mvc与mvvm
    • react-router
    • react懒加载
    • redux
    • setState源码分析
    • webpack+react从0项目构建
  • ts
    • Typescript编程书籍导读
    • 体操基础
  • 其他
    • gitbook简易配置教程
    • gitbook转pdf电子书
  • 微前端
    • pnpm
    • qiankun
    • single-spa源码分析
    • 几种微前端架构的选型
  • 转载
    • interview-1
    • interview-2
    • interview-3
    • 经验好文
  • 项目经验
    • 23年总结
    • [Arkts 学习笔记](项目经验/Arkts 学习笔记.md)
    • Grafana插件
    • JSDoc
    • electron-builder构建的安装包,安装时通过nsis脚本自动导入注册表
    • overflow-yautohiddenscroll和overflow-xvisible组合渲染异常
    • webpack
    • 前端工程化
    • 前端性能优化思路
    • 前端性能监控工具
    • 前端架构
    • 前端登录流程
    • 前端监控原理
    • 团队管理
    • 基于node实现简单server
    • 如何对业务进行深挖
    • 如何拉齐横向
    • 如何画图
    • 如何记录
    • 组件库
Powered by GitBook
On this page
  • 为什么需要懒加载
  • 如何做
  • import()动态引入
  • import() 的原理
  • React.lazy
  • loadable-components

Was this helpful?

  1. react

react懒加载

Previousreact-routerNextredux

Last updated 2 years ago

Was this helpful?

为什么需要懒加载

React应用都会使用Webpack等打包工具进行文件打包。打包是一个根据入口文件,查询各文件引入关系,最后将所有需要的文件合并到一个单独文件的过程。

随着我们项目需求的增大,这个单独的文件就会越来越大,首次加载往往会有好几M的文件。严重影响体验,所以我们需要拆分这个文件。

拆分文件的思路之一就是懒加载。即当组件需要被调用时才去加载

如何做

主流分为两种解决方案

  1. react官方提供的代码分割

  2. react官网推荐的

两种解决方案最大的区别在于方案2支持SSR(Server Side Rendering);

import()动态引入

写法样例

// 使用前
import { add } from './math';

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

import() 的原理

function importModule(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2);
    script.type = "module";
    script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`;

    script.onload = () => {
      resolve(window[tempGlobal]);
      delete window[tempGlobal];
      script.remove();
    };

    script.onerror = () => {
      reject(new Error("Failed to load module script with URL " + url));
      delete window[tempGlobal];
      script.remove();
    };

    document.documentElement.appendChild(script);
  });
}

React.lazy

  1. 使用React.lazy(()=>import(uri))形式引入组件

  2. 使用被引入的组件需要包裹在Suspense之中

写法样例

import React, { Suspense } from 'react';

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

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

思考:既然import()已经帮我们做了这么一个代码分割。那么我们为什么还需要用React.lazy()包一下?

答案:就是要把import()返回的是promise对象 转换成可以调用的组件

loadable-components

写法样例

import loadable from '@loadable/component'

const OtherComponent = loadable(() => import('./OtherComponent'))

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  )
}

思考:可以看到与React.lazy()方式主要差异就是他不需要包裹层,那么他是如何实现的?

答案: 定义了一个函数,函数返回一个普通react组件A。组件内部维护一个更新状态,默认是false,组件内部调用函数传参中返回的promise,当promise触发结束时。更新状态改为true,A组件渲染返回的子组件

思考:那么他可以实现包裹层中组件没有加载完出等待效果嘛?

答案: 当然可以,@loadable/component提供更完善的功能;

import()是符合的一种方式。当webpack遇到这种语法时,会自动进行代码分割。当模块被调用时,进行加载

关于使用import()时webpack的

React.lazy
loadable-components
ECMAScript提案
配置