ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

深入理解 React Lazy Loading:用 React.lazy 与 Suspense 构建高性能 React 应用

深入理解 React Lazy Loading:用 React.lazy 与 Suspense 构建高性能 React 应用 深入理解 React Lazy Loading用 React.lazy 与 Suspense 构建高性能 React 应用【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读本文是一份关于 React 懒加载Lazy Loading的完整实战指南源自 refine一个用于构建内部工具、后台管理面板与 B2B 应用的 React 框架官方博客的工程主题文章。全文将系统讲解懒加载的核心原理、React.lazy与动态import()的使用方式、Suspense回退 UI、错误边界ErrorBoundary、路由级与组件级代码分割并延伸到 SEO 考量、测试策略与性能指标。读完本文你将掌握如何在 React 应用包括基于 refine 构建的管理后台中按需加载代码块显著降低首屏加载体积、改善用户体验。什么是懒加载为什么要用它懒加载Lazy Loading是软件工程中一种通用的性能优化策略不仅适用于 Web 开发同样可用于桌面端与移动端开发。它的核心思路是只加载当前真正需要的资源而不是一次性下载全部内容。这样用户无需等待所有资源下载完毕就能开始使用网站或应用。懒加载在应用层面的价值体现在多个方面性能提升Improvement in Performance将首屏加载内容压到最小页面加载更快尤其适合内容量巨大的站点。用户不再需要等待全部资源下载完成才能操作。UI 元素按需加载Loading UI Elements懒加载不只作用于页面列表、图片等 UI 元素同样适用。例如一个详情页包含数百张图片如果全部在初始阶段加载性能会明显下降改为在图片即将进入视口viewport前才加载可以显著减少首屏的网络请求数量。用户体验User Experience更快的页面加载与响应时间能够提升用户留存率。相关研究显示约有 95% 的用户在网页加载超过 2 秒后会选择离开。懒加载让关键内容“先加载、快加载”从而留住用户。懒加载的工作原理懒加载的本质是削减初始页面加载时间。以一个博客网站为例它包含首页Home、列表页List和详情页Detail三类页面假设其体积分别为首页39KB列表页90KB详情页88KB如果加载首页时把三个页面全部加载总共需要下载 217KB。而通过代码分割code-splitting把各页面拆成独立 bundle、按需加载用户访问首页时只需下载 39KB加载速度自然大幅提升。这不仅是页面级策略——当详情页中有数百张图片、需要向服务器发起上百个请求时同样可以把图片加载推迟到它们即将滚入浏览器视口的那一刻。React.lazy按需动态加载组件React.lazy()是 React 提供的懒加载工具于React 16.6版本引入。它允许开发者把组件代码拆分为小块chunk按需加载从而减少初始下载的代码量。lazy是 React 包导出的一个函数import { lazy } from react;// 或者import React from react; React.lazy;React.lazy底层依赖ES6ECMAScript 6动态导入dynamic import允许在运行时动态加载模块。以工具函数为例普通静态导入是import { capitalizeFirstLetter } from ./utils;要把它变为按需加载改用动态import()import(./utils).then((utils) { console.log(utils.capitalizeFirstLetter(nnamdi chidume)); });这样utils会被从最终 bundle 中拆出仅在需要时才加载。对于组件先静态导入目标组件import LazyComponent from ./LazyComponent;再调用React.lazy传入一个调用import()并返回其 Promise 的回调函数路径传给import()const LazyComponent React.lazy(() import(./LazyComponent));LazyComponent将从主 bundle 中拆分出来页面初始加载时不会随主 bundle 一起下载而是在它真正被使用时才加载。以博客网站的首页为例首页上有指向详情页的链接懒加载详情页的写法如下import DetailPage from ./DetailPage; const DetailPage React.lazy(() import(./DetailPage)); export const HomePage () { return ( ul {this.props.blogs.map((blog, index) { return DetailPage blog{blog} /; })} /ul ); };此时DetailPage被拆成独立 bundle不再参与首页的初始加载。不过直接运行这段代码会报错React component suspended while rendering, but no fallback UI was specified.原因在于使用React.lazy加载的组件必须被Suspense包裹。Suspense为异步加载提供回退 UISuspense是 React 用于异步加载组件的特性与React.lazy配合使用。它既可以在组件获取期间显示加载指示器也可以在加载失败时渲染 fallback 组件。从 react 包导入import { Suspense } from react;将懒加载组件包裹在Suspense中Suspense LazyComponent / /Suspense但这并不是好的 UX 实践——用户完全不知道有一个组件正在加载。因此需要借助Suspense的fallback属性在懒加载组件尚未下载完成时展示一个 UI 提示。fallback可以接收字符串或任意 JSXSuspense fallback{Loading...} LazyComponent / /SuspenseSuspense fallback{divLoading.../div} LazyComponent / /Suspense捕获加载错误ErrorBoundary使用React.lazy时必须处理可能出现的加载错误例如网络错误。做法是把包含懒加载组件的Suspense再包进一个ErrorBoundary错误边界组件中。错误边界在 React 中的作用类似于 JavaScript 的 try-catch它捕获组件树中的错误避免整个应用崩溃。一个典型的错误边界组件class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { logService(error, errorInfo); } render() { return this.state.hasError ? ( h1Something went wrong./h1 ) : ( this.props.children ); } }当被包裹的组件树抛出错误时应用不会崩溃而是就地渲染Something went wrong.。组合使用方式ErrorBoundary Suspense fallback{divLoading.../div} LazyComponent / /Suspense /ErrorBoundary路由级代码分割Route-based Code SplittingReact 组件分为两类路由级组件Route-based与组件级组件Component-based。不需要也不应该对应用中所有组件都做懒加载——过度懒加载反而会引发严重问题。何时、对哪个组件做懒加载的判断并不容易但可以确定的是路由级组件是必须懒加载的对象。路由级组件是用户导航到指定 URL 时才加载的组件即基于 react-router 配置的页面。原始写法import React from react; import { BrowserRouter as Router, Routes, Route } from react-router-dom; import Home from ./Home; import About from ./About; const App () ( Router Routes Route path/ element{Home /} / Route path/about element{About /} / /Routes /Router );这里/与/about两个路由分别加载Home与About页面二者都是典型的路由级组件非常适合懒加载。改造后import React, { Suspense, lazy } from react; import { BrowserRouter as Router, Routes, Route } from react-router-dom; const Home React.lazy(() import(./Home)); const About React.lazy(() import(./About)); const App () ( Router Suspense Routes Route path/ element{Home /} / Route path/about element{About /} / /Routes /Suspense /Router );现在Home与About被拆分为各自独立的 bundle仅在对应路由被访问时加载应用整体 bundle 体积与页面加载时间都会显著下降。组件级代码分割Component-based Code Splitting组件级组件是不挂在页面路由上、用于展示应用中 UI 区块的普通组件本文前述的大部分示例都属于这一类。最适合做代码分割的组件是 Modal弹窗与 Aside侧边栏因为它们在网页加载时就被急切eagerly加载了而实际使用频率可能很低。与此相反Header、下拉菜单、按钮这类组件不应懒加载——它们是最常用、最容易被立即需要的 UI 元素懒加载反而会引入不必要的加载延迟。懒加载与 SEO 的考量懒加载通过只在需要时加载必要资源能显著改善网站性能与用户体验但同时也要保证搜索引擎能有效抓取内容。以下是需要留意的几个要点确保关键内容可访问Ensure Critical Content is Accessible不要懒加载重要内容尤其是首屏above-the-fold内容保证搜索引擎从一开始就能看到页面的关键部分。使用正确的 HTML 标记Use Proper HTML Markup即使对图片做懒加载仍要使用标准的img标签——可将src设为占位图用data-src或类似属性保存真实图片 URL确保搜索引擎能正确解析与索引图片。Intersection Observer API用它实现懒加载是一种轻量、快速监测文档中元素可见性的方式也符合支持 JavaScript 的主流搜索引擎的抓取逻辑。提供回退方案Provide Fallbacks始终为不支持懒加载的用户或爬虫提供回退例如渲染基础版本内容或保证无 JavaScript 环境下内容依然可用。关注搜索引擎抓取情况Watch out for search engine crawls借助 Google Search Console 等工具检查页面的抓取与索引情况如果发现重要内容缺失很可能是懒加载实现不当。正确的懒加载可以在性能提升与 SEO 之间取得平衡。测试懒加载组件懒加载组件需要专门的测试策略才能确保其正确、高效地加载配置测试环境Setting Up the Test Environment确保测试框架如 Jest支持懒加载即能配合 React 的Suspense与React.lazy工作。Mock 动态导入Mocking Dynamic Imports测试时可以通过 mock 动态导入控制组件的加载时机与方式。测试中使用 Suspense像应用代码一样在测试中用Suspense包裹懒加载组件。下面是一个基于 Jest 与 React Testing Library 的完整示例// LazyComponent.js import React from react; const LazyComponent () { return divLazy Loaded Component/div; }; export default LazyComponent; // App.js import React, { Suspense, lazy } from react; const LazyComponent lazy(() import(./LazyComponent)); const App () { return ( Suspense fallback{divLoading.../div} LazyComponent / /Suspense ); }; export default App; // App.test.js import React from react; import { render, screen } from testing-library/react; import testing-library/jest-dom/extend-expect; import App from ./App; test(loads and displays lazy component, async () { render(App /); // Check for fallback content expect(screen.getByText(Loading...)).toBeInTheDocument(); // Wait for lazy component to load const lazyElement await screen.findByText(Lazy Loaded Component); expect(lazyElement).toBeInTheDocument(); });测试先断言 fallback 内容Loading...出现再通过findByText异步等待懒加载组件真正渲染完成——这正是懒加载组件测试的核心流程。性能指标与测量工具为了量化懒加载带来的收益需要关注以下关键性能指标Core Web Vitals 体系First Contentful PaintFCP屏幕上绘制出任何内容所花费的时间。懒加载减小初始 bundle 体积从而改善 FCP。Time to InteractiveTTI应用真正可交互所需时间。初始阶段只加载必要内容有助于缩短 TTI。Largest Contentful PaintLCP页面最大内容元素变为可见所需时间可通过优化懒加载来改善。Cumulative Layout ShiftCLS页面生命周期中所有非预期布局偏移的总分。图片与组件懒加载到位后往往减少布局偏移CLS 因此更优。常用的测量工具包括LighthouseChrome DevTools 内置功能可审计性能、无障碍、最佳实践与 SEO。WebPageTest提供更深入的性能细节含胶片视图filmstrip与瀑布图waterfall charts。Google Analytics通过自定义指标持续追踪性能数据随时间的变化。Performance API浏览器内置的 Performance API可在应用代码中测量精确的时间点。从源码看懒加载在 refine 文档站中的实践本文出自 refine 官方博客。refine 是一个用于构建内部工具、后台面板、仪表盘与 B2B 应用的 React 框架其配套文档站本仓库documentation/目录基于 Docusaurus 构建本身就把懒加载的多种形态落到了实处可以作为参照依赖层面的 React 版本支持文档站使用react: ^17.0.2见 documentation/package.json而核心包refinedev/core支持react: ^18.0.0 || ^19.0.0见 packages/core/package.json。React.lazy自 React 16.6 起即为稳定特性因此在这些版本范围内均可放心使用。动态 import 的真实用例文档站的搜索栏在需要展示搜索弹窗时通过动态import()延迟加载 DocSearch 的弹窗模块、样式与本地样式文件见 documentation/src/theme/SearchBar/index.tsx。这正是“非首屏关键资源按需加载”思路的落地。原生图片懒加载实践文档站的自定义图片组件为img设置了loadinglazy属性见 documentation/src/components/image/index.tsx博客文章卡片同样如此见 documentation/src/theme/BlogPostItem/index.js利用浏览器原生能力对图片做懒加载——与本文“图片进入视口前再加载”的原则完全一致。结语我们从懒加载的定义与价值出发理解了它如何减少首屏加载体积、改善用户体验随后深入React.lazy函数与动态import()的用法学习了Suspense回退 UI 与 ErrorBoundary 错误捕获再分别针对路由级组件与组件级组件讨论了代码分割的取舍并延伸覆盖了 SEO 考量、测试策略与性能指标测量。React.lazy是 React 中让组件按需加载的强大特性组件只在真正需要时才被加载从而提升应用整体性能。结合Suspense的 fallback 提示与 ErrorBoundary 的兜底处理再配合正确的代码分割粒度选择你可以在任何 React 项目——包括基于 refine 构建的管理后台——中稳定地落地一套高效的懒加载方案。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表