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
我们使用 Vite JS 创建项目,并选择 React with TypeScript。
然后运行以下命令导航到刚刚创建的目录。
cd code-splitting-react
然后我们安装依赖项。
npm install
然后我们在代码编辑器中打开项目(在我的情况下是 VS 代码)。
code .
💢 第一步。
首先,我们要创建几个页面。我们创建文件夹src/pages,并在其中创建 6 个文件。这些文件非常简单,内容也很少。
请注意,我放置的唯一内容是一个具有与页面对应的名称的 div。
1-个人资料.tsx
export const Profile = () => {
return (
<div>Profile</div>
)
}
我们对以下 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';
现在让我们创建一个示例,说明如何在不应用代码拆分的情况下正常创建具有路由的应用程序。
我们安装 React Router Dom
npm install react-router-dom
创建一个文件夹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>
)
}
现在,我们在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
现在我们要稍微修改一下,模拟私有路由。因此,在同一个文件中,我们创建了两个新组件。
在这个组件中,我们将包含这些路由,这些路由将是私有的,也就是说,用户在通过身份验证之前将无法看到它们。
另外请注意,这里我们将展示。
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>
</>
)
}
然后是公共道路。
export const PublicRoutes = () => {
return (
<Routes>
<Route path='login' element={ <Login /> } />
<Route path='/*' element={<Navigate to='/login' replace />} />
</Routes>
)
}
最后,我们修改App组件。
我们创建一个常量来模拟身份验证。
然后,我们将根据该常量创建一个或另一个路由。
const isAuthenticated = false
const App = () => {
return (
<BrowserRouter>
<Routes>
{
(isAuthenticated)
? <Route path="/*" element={<PrivateRoutes />} />
: <Route path="/*" element={<PublicRoutes />} />
}
</Routes>
</BrowserRouter>
)
}
export default App
你可能会认为,因为我们只渲染某些路由,而不渲染其他路由,所以未渲染的路由不会被加载。但事实是,即使未渲染,屏幕上的公共或私有路由、所有组件、所有页面及其 CSS 和其他包也始终会被加载。
您可以在运行应用程序时进行检查,然后检查“网络”选项卡中的页面并通过 JS 文件对其进行过滤,您将看到所有页面是如何加载的,Login.tsx、Profile.tsx、About.tsx 等。
也许现在你不会注意到加载速度有什么问题,因为这个应用几乎没有内容。但想象一下,如果你安装了更多组件或软件包,即使你没有使用它,你的应用也会加载所有内容。
因此,让我们尝试通过代码拆分来解决这个问题。
💢 应用代码分割。
目前,我们有一个“身份验证”功能,可以控制我们是否访问私人页面。
但之前我们看到,无论是否通过身份验证,页面都会始终加载。
那么,如果用户只想登录,就没必要加载其他私有页面了。或者,如果用户已经通过身份验证,就不需要加载登录信息,直到用户决定注销。
为了应用代码分割,我们使用:
React.lazy:React 直接提供的功能,允许延迟加载导入。它是一个组件函数,接受另一个函数作为参数,最终返回一个 Promise,该 Promise 预期由 React 组件解析。
const Login = lazy(() => import('./pages/Login'));
但是,您可能会收到错误,因为惰性函数期望您希望它返回的组件是默认导出。
因此我们只需转到每个页面并添加其默认导出。
以pages/Login.tsx为例。我们将对所有页面执行相同的操作。
const Login = () => {
return (
<div>Login</div>
)
}
export default Login
然后我们创建其他页面并为其添加懒惰功能。
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' ));
现在,让我们讨论一下导入,以便它们不会与我们创建的新组件发生冲突
// import { About, Contact, FAQs, Profile, Login } from './pages'
但最后一步仍然缺失,因为如果我们看到我们的应用程序,它会给我们一个错误,这是因为我们需要一个组件来暂停组件的渲染,直到它的所有依赖项都加载完毕。
为此我们使用组件React 为我们提供了
import { lazy, Suspense } from 'react';
<Route
path='login'
element={
<Suspense>
<Login />
</Suspense>
}
/>
Suspense 也充当用户界面,因为它包含一个fallback属性,该属性必须接收一个 React 组件,该组件会一直显示,直到我们应用了lazy加载的组件完成加载。所以这里很适合放置加载组件。
import { lazy, Suspense } from 'react';
<Route
path='login'
element={
<Suspense fallback={<>Loading app...</>}>
<Login />
</Suspense>
}
/>
你需要将 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>
</>
)
}
您甚至可以创建一个包含路线的列表,并使用.map浏览它,以避免放置过多的 Suspense。
但如果我们现在再看看“网络”选项卡,事实是我们不会看到加载速度有很大差异,因为它是一个非常小的应用程序。
但是现在,将身份验证更改为 true,以便呈现路由的私有部分。
const isAuthenticated = true
注意 JS 文件,您会发现并非所有文件都已加载,只有 Profile.tsx 已加载,因为它是您当前正在查看的页面。
如果您开始使用导航栏在页面之间移动,您将看到它们在您访问的每个页面上是如何加载的,因此它们只会在您需要它们时才加载。
这就是我们如何应用代码分割来提高 React 应用程序的性能。
我也不是建议你对所有组件都使用 lazy 加载,因为这会导致加载时间更长。尽量只加载那些在初始渲染中不可见的组件。
💢结论。
代码拆分是大型 React 应用程序中的常见做法,它提供的速度提升可以决定用户是否继续使用 Web 应用程序或放弃它,因此即使是几分之一秒的缩短也可能意义重大。
希望以上内容能帮助你更好地理解这个主题。如果你知道其他不同或更好的方法来实现这个功能,欢迎留言评论。🙌
文章来源:https://dev.to/franklin030601/code-splitting-in-react-js-4o2g如果您有兴趣就某个项目与我联系,欢迎查看我的投资组合!富兰克林·马丁内斯·卢卡斯
🔵 别忘了在推特上关注我:@Frankomtz361