如何使用 React.js 实现无限滚动
介绍
任何应用程序,无论是网页、桌面还是移动应用程序,都拥有大量数据记录。用户可能出于各种原因想要在一个地方访问这些数据,这些原因与产品、物品、航班、火车、房屋等有关。
对于这样的功能,由于整体性能问题,很难一次性加载所有记录,所以我们需要一个替代方案。一个替代方案称为无限滚动。
什么是无限滚动?
无限滚动是一种基于无限滚动事件显示数据并仅在需要时加载数据的机制,以避免严重的性能问题。
基本上,无限滚动方法与分页相比非常方便,用户每次想要加载下一页的数据时都必须单击页码。
只有当我们想要连续加载属于同一层级的数据时,无限滚动机制才是可取的。否则,我们可以选择其他替代方案。
无限滚动功能似乎是分页的优雅替代品。然而,它并不是所有网站的答案。如果网站访问者想要实现特定类型的目标导向活动,例如当他们需要回溯或快速找到特定信息而又不费力时,无限滚动可能不适合您。
在本指南中,我们将使用自定义逻辑实现无限滚动。让我们来看一个例子。
实现自定义无限滚动
在 React 中,我们有两种选择来开发无限滚动。
- 使用第三方库
- 使用自定义无限滚动机制
在本指南中,我们将开发一个简单的自定义无限滚动机制,帮助我们根据滚动事件加载数据。
在开始之前,我们需要持续加载数据,因此,我们将使用一个虚拟/模拟 API 平台,该平台使用其官方 API 为我们提供虚假数据。我们将要使用的 URL 如下所示。
https://jsonplaceholder.typicode.com/photos
要调用 API,我们应该在应用程序中安装 Axios,它用于发出 HTTP 请求以从我们的应用程序中获取或保存数据。它是一个第三方库,因此我们可以使用以下npm命令安装它。
npm install axios
让我们创建一个名为ScrollComponent.jsx的新子组件,并创建一个像这样的状态对象。
import React, { Component } from "react";
import axios from "axios";
class ScrollComponent extends Component {
constructor() {
super();
this.state = {
photos: [],
loading: false,
page: 0,
prevY: 0
};
}
render() {
return (
<div className="container">
</div>
);
}
}
export default ScrollComponent;
在我们的滚动组件中,我们创建了一些状态值来存储来自 API 响应的照片,并创建了其他状态值来管理页面属性和加载行为。
现在,我们必须创建一个函数,其中包含使用 Axios 包从虚假 API 获取 API 数据的源代码。让我们创建一个这样的可重用函数。
getPhotos(page) {
this.setState({ loading: true });
axios
.get(
`https://jsonplaceholder.typicode.com/photos?_page=${page}&_limit=10`
)
.then(res => {
this.setState({ photos: [...this.state.photos, ...res.data] });
this.setState({ loading: false });
});
}
在此函数中,我们将加载状态值设置为true,表示正在从 API 加载数据。我们使用 Axios 以及 API URL 从服务器获取数据。
根据请求获得响应后,我们需要将数据存储到我们之前在此组件中创建的名为照片的单独数组中。
如果你注意到,我们已经结合了之前和当前的数据,只是因为我们将根据滚动事件连续调用此函数,并且它会将响应附加到照片数组中。
创建函数后,我们必须在组件加载后调用它,因此我们可以像这样从componentDidMount ()函数调用它。
componentDidMount() {
this.getPhotos(this.state.page);
}
我们已经配置了基本 API 函数,我们将从中调用该 API。我们还从componentDidMount()生命周期钩子中调用了getPhotos()函数,但这足以开发无限滚动。
现在,我们必须监听每个滚动事件行为,并根据滚动事件更新页码以便从 API 中获取新数据。
我们将使用交叉点观察器,它做两件事:
- 它描述了用于从目标元素获取 DOM 元素位置的 API。
- 它从 DOM 内容中获取元素的预加载和延迟状态。
让我们像这样更新componentDidMount()钩子。
componentDidMount() {
this.getPhotos(this.state.page);
var options = {
root: null,
rootMargin: "0px",
threshold: 1.0
};
this.observer = new IntersectionObserver(
this.handleObserver.bind(this),
options
);
this.observer.observe(this.loadingRef);
}
在这个钩子函数中,我们创建了几个选项:
- root:这是用于交叉点的根。
- rootMargin:类似于边距属性,用于以像素或百分比(%)为根提供边距值。
- 阈值:当交叉点的面积变化大于或等于我们在此示例中提供的值时,用于触发回调的数字。
除了这三个选项之外,我们还有一个实际的交叉观察函数,它包含两个不同的参数:
- 观察者回调函数名称
- 附加选项,例如根和阈值
通过使用交叉点观察者,我们可以监听目标元素的任何变化,如果有任何变化,那么就会触发回调函数。
现在我们来实现回调触发函数,它看起来像这样。
handleObserver(entities, observer) {
const y = entities[0].boundingClientRect.y;
if (this.state.prevY > y) {
const lastPhoto = this.state.photos[this.state.photos.length - 1];
const curPage = lastPhoto.albumId;
this.getPhotos(curPage);
this.setState({ page: curPage });
}
this.setState({ prevY: y });
}
在此函数中,我们将根据正在滚动的目标元素配置页码。我们将保存正在滚动的最后一页,并根据当前页面,fetch API 开始发挥作用并从服务器获取最新数据。
一旦我们滚动数据,当前页面将与前一页的页码一起更新为状态。
这就是我们在本指南中想要开发的内容,但这远不是结束。我们遗漏了显示照片并将其渲染到 DOM 中的关键步骤。
用给定的源代码替换render()函数。
render() {
// Additional css
const loadingCSS = {
height: "100px",
margin: "30px"
};
// To change the loading icon behavior
const loadingTextCSS = { display: this.state.loading ? "block" : "none" };
return (
<div className="container">
<div style={{ minHeight: "800px" }}>
{this.state.photos.map(user => (
<img src={user.url} height="100px" width="200px" />
))}
</div>
<div
ref={loadingRef => (this.loadingRef = loadingRef)}
style={loadingCSS}
>
<span style={loadingTextCSS}>Loading...</span>
</div>
</div>
);
}
渲染功能包含不同的配置,如下所述。
像这样为加载内容时显示的图标创建一些附加样式。
const loadingCSS = {
height: "100px",
margin: "30px"
};
用于更改加载图标的类属性的另一种 CSS 样式称为loadingTextCSS,如下所示。
const loadingTextCSS = { display: this.state.loading ? "block" : "none" };
最后,在返回函数中,我们使用了状态数组,称为照片,其中包含来自 API 响应的照片列表。
<div style={{ minHeight: "800px" }}>
{this.state.photos.map(user => (
<img src={user.url} height="100px" width="200px" />
))}
</div>
除了照片列表,我们还根据加载参考配置了加载图标,这样只要我们向下滚动到目标元素,它就会显示加载图标。当加载过程完成后,加载图标就会消失。
<div
ref={loadingRef => (this.loadingRef = loadingRef)}
style={loadingCSS}
>
<span style={loadingTextCSS}>Loading...</span>
</div>
我们已经完成了 HTML 内容。现在,如果我们运行此示例,我们将获得每页的初始 10 条记录,因为我们已经像这样使用 API 配置了附加参数。
https://jsonplaceholder.typicode.com/photos?_page=${page}&_limit=10
因此当用户向下滚动页面时,页码将频繁更新;但页面限制保持不变,因此每次将有 10 条记录添加到数组中并渲染到 DOM 中。
这是使用交叉观察器获取目标元素的位置并将移动返回到 DOM 的完整过程。
使用第三方库实现无限滚动
在本指南中,我们使用自定义实现开发了无限滚动,但我们也可以使用第三方库。其中包括:
- react-infinite-scroller
- 反应无限滚动组件
- react-infinite-scroll
- react-loading-infinite-scroller
- react-infinite-scroll-hook
还有更多软件包可用,因此请根据您的项目需求明智地选择。
结论
无限滚动正在成为一种流行的基于滚动事件加载数据的方式,当用户到达页面底部时,滚动事件就会连续加载数据。
在本指南中,我们学习了在 ReactJS 中实现无限滚动的自定义方法,但我们也可以使用多个第三方库来实现相同的结果。我希望本指南有一天能对你有所帮助。如果您有任何疑问,请随时联系Codealphabet。
了解更多
探索 Pluralsight 的这些 React 课程以继续学习:
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~