React组件实现动态导入的几种方案

1. 背景

在React应用中,当我们使用这样的语句导入某个模块(例如:一个组件)的时候,就称之为静态导入

TypeScript 复制代码
import sth from 'module1'

凡是被静态导入的模块,都会被打包到初始的bundle里面

如果一个应用内所有模块都使用静态导入,会导致

  • 初始bundle的体积较大
  • 浏览器加载bundle的速度较慢

因此:针对不需要被包含在首次渲染的模块,可以考虑使用动态导入,这样可以减少初始bundle的体积,从而提升首次渲染的性能

以组件为例,符合以下特征的组件其实都不需要被包含在首次渲染中

  • 依赖用户交互行为的 -> Import on interaction
  • 首屏不可见的 -> Import in viewport
  • 不属于当前路由的 -> Route based splitting

2. Import on interaction

发生交互行为后(例如点击按钮),再加载组件

2.1 React Lazy

使用React提供的lazy导入组件

  • 使用lazy函数导入组件
  • 使用Suspense对组件进行包裹,并设置fallback来展示组件加载中的状态
TypeScript 复制代码
import { Suspense, lazy, useState } from 'react'
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'

const ComponentB = lazy(() => import('./ComponentB'))

export default function () => {
  const [visible, setVisible] = useState(false)
  
  function toggeleVisible() {
    setVisible(v => !v)
  }
  
  return (
    <Suspense fallback={<p>loading...</p>}>
      <ComponentA />
      <button onClick={toggleVisible}>click me to toggle ComponentC</button>
      {
        visible && <ComponentC />
      }
    </Suspense>
  )
}

2.2 import()

EsModule提供的import函数返回的是一个promise,值为module

通过import函数拿到组件的引用后,可以通过createElement的方式创建一个jsx元素进行渲染

TypeScript 复制代码
import { createElement, useState } from 'react'
import ComponentA from './ComponentA'

export default function () => {
  const [componentC, setComponentC] = useState(null)
  
  function showComponentC() {
    import('./ComponentC')
      .then(module => module.default)
      .then(component => {
        setComponentC(createElement(component))
      })
  }
  
  function hideComponentC() {
    setComponentC(null)
  }
  
  return (
    <>
      <ComponentA />
      <button onClick={() => {
        if (componentC) {
          hideComponentC()
        } else {
          showComponentC()
        }
      }}>
        click me to toggle ComponentC
      </button>
      {componentC}
    </>
  )
}

需要注意的是,使用Babel的时候,需要用@babel/plugin-syntax-dynamic-import插件确保Babel能够进行正确的转译

3. Import in viewport

当组件对应的UI进入视窗内的时候,再加载组件

下面提到的这两个库都是基于IntersectionObserver这个API实现的

3.1 react-loadable-visibility

使用 react-loadable-visibility

TypeScript 复制代码
import LoadableVisibility from "react-loadable-visibility/react-loadable"
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'

const ComponentC = LoadableVisibility({
  loader: () => import('./ComponentC')
  loading: <p>Loading...</p>
})

const App = () => {
  return (
    <>
      <ComponentA />
      <ComponentB />
      <ComponentC />
    </>
  )
}

export default App

3.2 react-lazyload

使用react-lazyload

TypeScript 复制代码
import LazyLoad from 'react-lazyload'
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'

const App = () => {
  return (
    <>
      <ComponentA />
      <ComponentB />
      <LazyLoad height='300px'>
        <ComponentC />
      </LazyLoad>
    </>
  )
}

export default App

相比于react-loadable-visibility,react-lazyload的功能更加强大,因为它提供了更多的API,让开发者能够通过这些API进行灵活的自定义配置,例如:

  • offset:如果需要提前加载组件,例如在视窗下边缘距离组件100px时就进行加载,可以设置offset为100

  • placeholder:组件未加载时的占位符

4. Route based splitting

基于路由来分割bundle,每个路由对应的根组件单独生成一个bundle

TypeScript 复制代码
import { RouteConfig } from 'react-router-config'
import { lazy } from 'react'

export const routes: RouteConfig[] = [
  {
    path: '/list',
    component: lazy(() => import('./src/List'))
  },
  {
    path: '/detail',
    component: lazy(() => import('./src/Detail'))
  }
]

参考资料

相关推荐
鬼手点金7 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
蛋蛋的就会顺顺的8 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday8 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室8 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan8 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床8 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a10 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台10 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li11 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
屏什么录11 小时前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发