【优秀译文】React无限滚动之实用指北原文地址 说明 随着网页设计和用户体验原则的快速发展,无限滚动已成为一个显著特征
说明
随着网页设计和用户体验原则的快速发展,无限滚动已成为一个显著特征,尤其是在社交媒体平台、电子商务网站和内容丰富的网站上。但究竟什么是无限滚动?
无限滚动是一种网页设计技术,它允许用户连续滚动浏览内容,而无需分页或点击 下一步 按钮。当用户接近显示内容的末尾时,会自动获取并显示更多内容,给人一种 无限 数据量的错觉。这种技术能让用户保持专注;他们不需要中断浏览来加载更多内容。
在本指南中,我们将通过创建一个基于卡片的星球浏览器来实现无限滚动。当用户滚动时,他们将发现更多的星球,享受无缝的用户体验。在制作此应用程序的同时,我们还将探讨无限滚动可能带来的潜在性能问题,并揭示缓解这些问题的优化策略。
先决条件
在开始之前需要具备一些先决条件:
- 基本了解 HTML、CSS 和 JavaScript:掌握 HTML、CSS 和 JavaScript 的基础知识将大有裨益。
- React 知识:由于我们使用 React 构建应用程序,因此掌握其概念和组件的工作原理将非常有价值。如果您是 React 的新手,请参考 React 官方文档以快速了解相关概述。
- Node.js 和 npm:您需要在系统中安装 Node.js 和 npm(Node 包管理器)。如果尚未安装,可以从 Node.js 官方网站下载并安装。
- Git:确保您的计算机上安装了 Git。如果没有,可以从 Git 网站下载。
开始吧
在开始构建我们的星球探索器之前,我们需要一个基础。幸运的是,为了节省在模板代码上花费的时间,并专注于我们项目的目标,我们在单独的分支中为您准备了一个启动模板。
该模板已包含预定义的文件夹结构和基本组件,因此我们无需从头开始。
克隆一个项目启动模板
要获取启动模板,请运行以下命令
git clone https://github.com/TropicolX/space-explorer-scroll.git
cd space-explorer-scroll
git checkout starter
npm install
这样,您就可以安装所有必要的文件和依赖项了。
文件夹结构
让我们先熟悉一下工作区的结构:
-
/src:这是我们项目的核心所在。
-
/components:React 组件的目录:用于存放 React 组件的目录。
-
/PlanetImages:包含每个行星图像的单独 JSX 文件和用于无限滚动的随机 JSX 文件。
-
Planet.jsx:该组件将渲染单个行星卡片。
-
Stars.jsx:用于创建星空背景效果。
-
-
App.css:应用程序的主要样式文件。
-
App.jsx:项目的核心,我们将在此管理我们的状态并渲染主要组件。
-
index.css:包含全局样式。
-
main.jsx:React 应用程序的入口点。
-
utils.js:该文件包含实用功能,例如为我们的行星生成随机颜色的函数。
-
现在我们已经设置好了工作区,让我们开始制作太空探索器的主要结构吧。
构建基本结构
让我们开始设置行星探索器的界面。应用程序应包含一个卡片列表,每张卡片代表一个星球,左侧为图像,右侧为该星球的详细信息。
首先,通过导航到项目目录并输入以下命令启动开发服务器:
npm run dev
我们应该有与下面类似的东西:
接下来,我们来设置初始计划列表。在 App.jsx
文件中添加以下代码:
import { useState } from "react";
import Planet from "./components/Planet";
...
function App() {
const [planets, setPlanets] = useState(planetsInSolarSystem);
return (
<div className="universe">
...
<div className="planets">
{planets.map((planet) => (
<Planet key={planet.name} data={planet} />
))}
</div>
</div>
);
}
export default App;
在上面的代码中:
- 我们用一个行星对象数组来启动行星状态。
- 然后,我们映射行星数组,以呈现行星组件列表。
基本结构设置完成后,我们的应用程序将以卡片格式显示行星列表。
使用 Intersection Observer 实现无限滚动
了解 Intersection Observer
Intersection Observer API 是一款功能强大的工具,可让您有效地跟踪和响应元素相对于其父容器或视口的可见性变化。
在本例中,我们将使用它来检测加载中的旋转器元素何时进入视口。当它进入视口时,这将成为我们加载更多星球卡的提示。
点击深入了解 Intersection Observer API
使用 Intersection Observer
<div className="planets">
{planets.map((planet) => (
<Planet key={planet.name} data={planet} />
))}
</div>
<div ref={loaderRef} className="spinner"></div>
现在,让我们深入研究一下逻辑。添加以下代码片段:
import { useState, useEffect, useRef, useCallback } from "react";
...
function App() {
const [planets, setPlanets] = useState(...);
const [offset, setOffset] = useState(0);
const loaderRef = useRef(null);
const loadMorePlanets = useCallback(async () => {
try {
const response = await fetch(
`https://planets-api-rho.vercel.app/api/planets?offset=${offset}`
);
const data = await response.json();
setPlanets([...planets, ...data]);
setOffset((previousOffset) => previousOffset + limit);
} catch (error) {
console.error(error);
}
}, [offset, planets]);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
const firstEntry = entries[0];
if (firstEntry.isIntersecting) {
// Load more planets when the loader is visible
loadMorePlanets();
}
});
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
// Clean up the observer on component unmount
return () => observer.disconnect();
}, [loadMorePlanets]);
return (
...
);
}
让我们来分解代码的每一部分:
-
状态管理和数据获取
- 偏移量跟踪当前偏移量,以便获取更多行星。
- loaderRef 用于保存加载旋转器元素的引用。
- loadMorePlanets 函数是使用 useCallback 钩子定义的。这种优化可确保函数引用在不同渲染中保持不变,除非其依赖关系(偏移量和行星)发生变化。
- 在 loadMorePlanets 函数中,我们使用 fetch 函数从远程 API 异步获取行星数据。我们会追加偏移参数,以便对数据进行分页。收到数据后,我们会将其与现有的行星连接起来,更新行星状态,并更新偏移量,以便将来进行分页。
-
Intersection Observer 对无限滚动的作用
- 在 useEffect 钩子中,我们创建了一个 IntersectionObserver 实例,用于监控加载旋转器的可见性。构造函数会接收一个回调函数,并在观察到的元素的交叉状态发生变化时调用该函数。
- 在回调函数中,我们访问代表观察元素数组的条目参数。我们只观察一个元素(加载旋转器),因此使用 entries[0] 访问第一个条目。
- 当加载旋转器在视口中变得可见时(isIntersecting 为 true),回调函数会触发 loadMorePlanets 函数来获取更多行星。
- 设置好交集观察器后,我们将其附加到 loaderRef.current 元素上。
- 当组件卸载时,观察器将断开连接,以防止内存泄漏。
- useEffect 钩子依赖于 [loadMorePlanets],以确保它能响应 loadMorePlanets 函数的变化。这个依赖关系非常重要,因为 loadMorePlanets 函数的引用可能会因依赖关系而发生变化。
这样,你就实现了无限滚动!当用户向下滚动时,Intersection Observer 将检测加载器何时可见,并触发 loadMorePlanets 函数。
优化和注意事项
无限添加内容的潜在性能问题
每当用户接近页面底部、获取并呈现新内容时,我们就会向 DOM 添加更多节点。随着内容的增加,这可能会
- 增加内存使用量:每个新的 DOM 元素都会占用内存。当我们无限添加更多元素时,可能会降低设备的运行速度,尤其是旧设备。
- 增加 CPU 占用:尤其是复杂的布局和 CSS 样式/动画。随着元素数量的增加,布局重新计算等操作可能需要更长的时间。
提高虚拟列表的性能
一种流行的优化方法是使用虚拟化列表(或窗口)。其概念很简单:只呈现当前视图中(或略微偏离屏幕)的项目,并在用户滚动时循环使用 DOM 节点。虚拟化列表具有多种优势,例如
- 一致的性能:通过只呈现项目的子集,无论列表的总大小如何,内存和 CPU 的使用量都基本保持不变。
- 更快的初始渲染:由于页面初始渲染的项目较少,因此加载和交互速度更快。
对于 React 来说,react-window 或 react-virtualized 等库提供了实现此功能的组件和钩子。如果您决定涉足这一领域,它们将是一个很好的起点!
进一步优化的工具和库
- React-query 或 SWR:如果您要从 API 获取数据,react-query 或 SWR 等库可以处理缓存、后台数据获取以及其他开箱即用的优化功能。
- React 无限滚动组件:为了简化实现无限滚动的过程,您可以考虑使用 react-infinite-scroll-component 等库。这些库提供预建组件,可为您处理大部分复杂问题。它们提供自动加载、加载指示器和可定制的阈值等功能,用于触发加载更多内容。
结论
在本指南中,我们在 React 应用程序中实现了无限滚动。我们首先制作了星球探索者的用户界面。然后,我们实现了无限滚动功能,让用户可以不断发现新的星球。
最后,我们讨论了为保持性能和用户满意度而应考虑的潜在隐患和技术优化。
如果考虑周全,无限滚动可以显著提高用户参与度,使内容消费无缝衔接。不过,必须记住的是,与任何工具一样,只有适合内容和用户需求,才能发挥最大功效。
转载自:https://juejin.cn/post/7296705389856538675