React JS 中的代码拆分

2025-06-05

React JS 中的代码拆分

当您的应用程序增长时,提高初始加载速度以使其更小将是相当重要的,从而避免用户因为等待加载而离开我们的应用程序。

为此,我们可以使用代码分割,这将对我们的应用程序有很大帮助。

注意:要理解这篇文章,您必须具有 React Router DOM 基础,因为我们将使用一个库来解释代码拆分。

 

目录。

📌需要用到的技术

📌什么是代码拆分?

📌创建项目。

📌第一步。

📌应用代码拆分。

📌结论。

 

💢 要使用的技术。

  • React JS v18.2.0
  • React 路由器 dom v6.7.0
  • Vite JS v4.0.0
  • TypeScript v4.9.3

💢 什么是代码拆分?

首先,你需要了解大多数框架的工作原理。
由于许多框架将所有依赖项捆绑到一个大文件中,因此可以轻松地将 JavaScript 添加到 HTML 页面。
理论上,以这种方式捆绑 JavaScript 应该可以加快页面加载速度并减少页面需要处理的流量。

但是随着应用程序的增长,其捆绑包的大小也会增长,并且在某些时候,其捆绑包会变得非常大,以至于需要很长时间才能加载。

这时就需要代码拆分技术了。代码拆分是指将代码拆分成多个包或组件,以便按需或并行加载。这意味着它们只有在需要时才会加载。

页面仍然会加载相同数量的代码,但不同之处在于页面可能不会执行其加载的所有代码。

代码分割的好处是:

  • 网站加载和显示内容的速度变得更快。
  • 交互时间得到改善。
  • 不与网页互动而放弃网页的用户百分比会下降。

💢 创建项目。

我们将为该项目命名:(code-splitting-react可选,您可以随意命名)。

npm create vite@latest
Enter fullscreen mode Exit fullscreen mode

我们使用 Vite JS 创建项目,并选择 React with TypeScript。

然后运行以下命令导航到刚刚创建的目录。

cd code-splitting-react
Enter fullscreen mode Exit fullscreen mode

然后我们安装依赖项。

npm install
Enter fullscreen mode Exit fullscreen mode

然后我们在代码编辑器中打开项目(在我的情况下是 VS 代码)。

code .
Enter fullscreen mode Exit fullscreen mode

💢 第一步。

首先,我们要创建几个页面。我们创建文件夹src/pages,并在其中创建 6 个文件。这些文件非常简单,内容也很少。

请注意,我放置的唯一内容是一个具有与页面对应的名称的 div。

1-个人资料.tsx

export const Profile = () => {
    return (
        <div>Profile</div>
    )
}
Enter fullscreen mode Exit fullscreen mode

我们对以下 4 个页面也进行同样的操作

2- 关于.tsx
3- 联系.tsx
4- 常见问题.tsx
5- 登录.tsx

在这个文件中我们将只导出每个页面,也就是说我们将把它用作一个桶文件。

6- index.ts

export * from './About';
export * from './Contact';
export * from './FAQs';
export * from './Login';
export * from './Profile';
Enter fullscreen mode Exit fullscreen mode

现在让我们创建一个示例,说明如何在不应用代码拆分的情况下正常创建具有路由的应用程序。

我们安装 React Router Dom

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

创建一个文件夹src/components并创建一个文件NavBar.tsx

import { Link } from 'react-router-dom';

export const NavBar = () => {
    return (
        <nav>
            <Link to='/home'>Home</Link>
            <Link to='/about'>About</Link>
            <Link to='/contact'>Contact</Link>
            <Link to='/faqs'>FAQs</Link>
        </nav>
    )
}
Enter fullscreen mode Exit fullscreen mode

现在,我们在src/App.tsx文件中删除其所有内容并创建一个新组件。

import { BrowserRouter, Navigate } from 'react-router-dom';
import { NavBar } from './components/NavBar';
import { About, Contact, FAQs, Profile, Login } from './pages'

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path='profile' element={ <Profile /> } />
        <Route path='contact' element={ <Contact /> } />
        <Route path='about' element={ <About /> } />
        <Route path='faqs' element={ <FAQs /> } />
        <Route path='login' element={ <Login /> } />

        <Route path='/*' element={<Navigate to='/login' replace />} />
      </Routes>
    </BrowserRouter>
  )
}
export default App
Enter fullscreen mode Exit fullscreen mode

现在我们要稍微修改一下,模拟私有路由。因此,在同一个文件中,我们创建了两个新组件。

在这个组件中,我们将包含这些路由,这些路由将是私有的,也就是说,用户在通过身份验证之前将无法看到它们。
另外请注意,这里我们将展示

export const PrivateRoutes = () => {
  return (
    <>
      <NavBar />
      <Routes>
        <Route path='profile' element={ <Profile /> } />
        <Route path='about'   element={ <About />   } />
        <Route path='contact' element={ <Contact /> } />
        <Route path='faqs'    element={ <FAQs />    } />

        <Route path='/*'      element={<Navigate to='/profile' replace />} />
      </Routes>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

然后是公共道路。


export const PublicRoutes = () => {
  return (
    <Routes>
      <Route path='login' element={ <Login /> } />

      <Route path='/*' element={<Navigate to='/login' replace />} />
    </Routes>
  )
}
Enter fullscreen mode Exit fullscreen mode

最后,我们修改App组件。
我们创建一个常量来模拟身份验证。
然后,我们将根据该常量创建一个或另一个路由。

const isAuthenticated = false

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        {
          (isAuthenticated)
            ? <Route path="/*" element={<PrivateRoutes />} />
            : <Route path="/*" element={<PublicRoutes />} />
        }
      </Routes>
    </BrowserRouter>
  )
}
export default App
Enter fullscreen mode Exit fullscreen mode

你可能会认为,因为我们只渲染某些路由,而不渲染其他路由,所以未渲染的路由不会被加载。但事实是,即使未渲染,屏幕上的公共或私有路由、所有组件、所有页面及其 CSS 和其他包也始终会被加载。

您可以在运行应用程序时进行检查,然后检查“网络”选项卡中的页面并通过 JS 文件对其进行过滤,您将看到所有页面是如何加载的,Login.tsx、Profile.tsx、About.tsx 等。

也许现在你不会注意到加载速度有什么问题,因为这个应用几乎没有内容。但想象一下,如果你安装了更多组件或软件包,即使你没有使用它,你的应用也会加载所有内容。

因此,让我们尝试通过代码拆分来解决这个问题

💢 应用代码分割。

目前,我们有一个“身份验证”功能,可以控制我们是否访问私人页面。
但之前我们看到,无论是否通过身份验证,页面都会始终加载。

那么,如果用户只想登录,就没必要加载其他私有页面了。或者,如果用户已经通过身份验证,就不需要加载登录信息,直到用户决定注销。

为了应用代码分割,我们使用:

React.lazy:React 直接提供的功能,允许延迟加载导入。它是一个组件函数,接受另一个函数作为参数,最终返回一个 Promise,该 Promise 预期由 React 组件解析。

const Login = lazy(() => import('./pages/Login'));
Enter fullscreen mode Exit fullscreen mode

但是,您可能会收到错误,因为惰性函数期望您希望它返回的组件是默认导出。

因此我们只需转到每个页面并添加其默认导出。

pages/Login.tsx为例。我们将对所有页面执行相同的操作。

const Login = () => {
    return (
        <div>Login</div>
    )
}
export default Login
Enter fullscreen mode Exit fullscreen mode

然后我们创建其他页面并为其添加懒惰功能。

const Profile = lazy(() => import('./pages/Profile'));
const About   = lazy(() => import('./pages/About'  ));
const Contact = lazy(() => import('./pages/Contact'));
const FAQs    = lazy(() => import('./pages/FAQs'   ));
const Login   = lazy(() => import('./pages/Login'  ));
Enter fullscreen mode Exit fullscreen mode

现在,让我们讨论一下导入,以便它们不会与我们创建的新组件发生冲突

// import { About, Contact, FAQs, Profile, Login } from './pages'
Enter fullscreen mode Exit fullscreen mode

但最后一步仍然缺失,因为如果我们看到我们的应用程序,它会给我们一个错误,这是因为我们需要一个组件来暂停组件的渲染,直到它的所有依赖项都加载完毕。

为此我们使用组件React 为我们提供了

import { lazy, Suspense } from 'react';

<Route 
    path='login' 
    element={
        <Suspense> 
            <Login />
        </Suspense>
    } 
/>
Enter fullscreen mode Exit fullscreen mode

Suspense 也充当用户界面,因为它包含一个fallback属性,该属性必须接收一个 React 组件,该组件会一直显示,直到我们应用了lazy加载的组件完成加载。所以这里很适合放置加载组件。

import { lazy, Suspense } from 'react';

<Route 
    path='login' 
    element={
        <Suspense fallback={<>Loading app...</>}> 
            <Login />
        </Suspense>
    } 
/>
Enter fullscreen mode Exit fullscreen mode

你需要将 Suspense 添加到每个应用了延迟函数的页面。文件如下所示。

import { lazy, Suspense } from 'react';
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
import { NavBar } from './components/NavBar';
// import { About, Contact, FAQs, Profile, Login } from './pages'

const Profile = lazy(() => import('./pages/Profile'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
const FAQs = lazy(() => import('./pages/FAQs'));
const Login = lazy(() => import('./pages/Login'));

const isAuthenticated = false

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        {
          (isAuthenticated)
            ? <Route path="/*" element={<PrivateRoutes />} />
            : <Route path="/*" element={<PublicRoutes />} />
        }
      </Routes>
    </BrowserRouter>
  )
}
export default App

export const PublicRoutes = () => {
  return (
    <Routes>
      <Route path='login' element={<Suspense fallback={<>...</>}> <Login /></Suspense>} />
      <Route path='/*' element={<Navigate to='/login' replace />} />
    </Routes>
  )
}

export const PrivateRoutes = () => {
  return (
    <>
      <NavBar />
      <Routes>
        <Route path='profile' element={<Suspense fallback={<>...</>}> <Profile /></Suspense>} />
        <Route path='about' element={<Suspense fallback={<>...</>}> <About /></Suspense>} />
        <Route path='contact' element={<Suspense fallback={<>...</>}> <Contact /></Suspense>} />
        <Route path='faqs' element={<Suspense fallback={<>...</>}> <FAQs /></Suspense>} />
        <Route path='/*' element={<Navigate to='/profile' replace />} />
      </Routes>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

您甚至可以创建一个包含路线的列表,并使用.map浏览它,以避免放置过多的 Suspense。

但如果我们现在再看看“网络”选项卡,事实是我们不会看到加载速度有很大差异,因为它是一个非常小的应用程序。

但是现在,将身份验证更改为 true,以便呈现路由的私有部分。

const isAuthenticated = true
Enter fullscreen mode Exit fullscreen mode

注意 JS 文件,您会发现并非所有文件都已加载,只有 Profile.tsx 已加载,因为它是您当前正在查看的页面。

如果您开始使用导航栏在页面之间移动,您将看到它们在您访问的每个页面上是如何加载的,因此它们只会在您需要它们时才加载。

这就是我们如何应用代码分割来提高 React 应用程序的性能。

我也不是建议你对所有组件都使用 lazy 加载,因为这会导致加载时间更长。尽量只加载那些在初始渲染中不可见的组件。

💢结论。

代码拆分是大型 React 应用程序中的常见做法,它提供的速度提升可以决定用户是否继续使用 Web 应用程序或放弃它,因此即使是几分之一秒的缩短也可能意义重大。

希望以上内容能帮助你更好地理解这个主题。如果你知道其他不同或更好的方法来实现这个功能,欢迎留言评论。🙌

如果您有兴趣就某个项目与我联系,欢迎查看我的投资组合!富兰克林·马丁内斯·卢卡斯

🔵 别忘了在推特上关注我:@Frankomtz361

文章来源:https://dev.to/franklin030601/code-splitting-in-react-js-4o2g
PREV
使用 React Hook Form 实现动态表单。📝
NEXT
使用 GSAP + React 实现动画