欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

react Suspense / lazy / loadable 实现路由懒加载

程序员文章站 2024-03-14 20:42:17
...

目录

前言

为什么要代码分割?

第三方库方案——react-loadble

“lazy 方法 + Suspense 组件”方案


前言

在 16.6 版本之前,代码分割通常是由第三方库来完成的,比如 react-loadble(核心思路为: 高阶组件 + webpack dynamic import)。在 16.6 版本中提供了 Suspense 和 lazy 这两个方法来实现代码分割。

 

为什么要代码分割?

React 项目打包时,如果不进行异步组件的处理,那么所有页面所需要的 js 都在同一文件中(bundle.js),整个js文件很大,从而导致首屏加载时间过长。为了解决这个的问题,现在像 Webpack、 Browserify 等打包器都支持了代码分割技术。

 

第三方库方案——react-loadble

react-loadable 插件是一个轻量级的代码分割组件,是一个用于加载具有动态导入的组件的高阶组件。

英文官方文档:https://www.npmjs.com/package/react-loadable

中文翻译版文档:https://www.jianshu.com/p/462bb9d1c982

react-loadable 的使用:React 性能优化之组件动态加载(react-loadable)

我的实践:

// ./src/utils/loadable
import React from "react";
import { Spin } from "antd";
import Loadable from "react-loadable";

export default (loader) => {
  return Loadable({
    loader,
    loading() {
      return (
        <div style={{width:"100%", height:"100vh", display:'flex', justifyContent:"center", alignItems:"center"}}>
          <Spin />
        </div>
      );
    },
  });
};
// routes.js
import loadable from "./src/utils/loadable";

const Home = loadable(() => import("./project/Home"));

const routes = [
  {
    path: "/:projectName/Home",
    component: Home,
    title: "首页",
  },
]

export default routes;

 

 

“lazy 方法 + Suspense 组件”方案

  • React.lazy 来实现 React 组件的懒加载。
  • Suspense 组件用来处理异步加载资源时页面应该如何显示的问题。

lazy 方法 + Suspense 组件 的使用示例:

import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

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

上述代码中还用到了import()方法,下面介绍下:

import() 函数是由 TS39 提出的一种动态加载模块的规范实现,其返回是一个 promise。

import() 源码如下:

function import(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);
  });
}