首页  >  文章  >  web前端  >  在 React 中构建无限滚动组件

在 React 中构建无限滚动组件

WBOY
WBOY原创
2024-08-26 21:45:021101浏览

介绍

我们在应用程序和网页中看到无限滚动,尤其是希望我们滚动的社交媒体。虽然无意识地滚动不好,但构建自己的无限滚动是很棒的。作为开发人员,我们应该尝试重新创建我们在网上冲浪时看到的组件。它可以挑战您在实现某些组件时了解更多信息并跳出框框进行思考。

此外,如果您希望在应用程序中实现无限滚动,那么您可以按照指南创建自己的滚动。您可以添加自己的代码来改善滚动的行为。

在本文中,我们将从头开始构建一个无限滚动组件。它将涵盖以下主题:

  • 环境设置
  • 构建组件
  • 添加 CSS
  • 优化无限滚动

现在,让我们开始吧。

环境设置

我们将使用 CRA 创建基本的 React 应用程序。您可以运行以下命令来做到这一点:

    npx create-react-app infinite-scroll

如果您想使用 Vite 或 NextJS 也可以。除了细微的变化外,其他内容将保持不变。

注意:要运行此命令,您需要预先安装 NodeJS。 另外,从 CRA 中删除一些不必要的样板代码。

我们需要一个依赖项来从 API 获取数据。设置好React后,我们就可以使用以下命令安装Axios:

    npm install axios

现在,我们已准备好创建组件。

应用程序组件

我们将构建一个组件,从 Tmdb API 获取流行电影数据。您可以从他们的网站免费获取他们的 API 密钥。让我们首先构建他们获取数据的位置,然后添加无限滚动功能。

这是应用程序组件的代码:

App.js

    import "./App.css";
    import { useState, useEffect } from "react";
    import axios from "axios";
    import { MovieCard } from "./MovieCard";

    function App() {
      const [page, setPage] = useState(1); // for number of page in tmdb 
      const [data, setData] = useState([]); // storing the fetched data
      const [loading, setLoading] = useState(false); // for setting loading state

      // fetching and stroring the data in the state
      const fetchMovie = async () => {
        const URL = `https://api.themoviedb.org/3/movie/popular?language=en-US&page=${page}`;
        const data = await axios.get(URL, {
          headers: {
            Authorization:
              "Bearer API KEY",
            Accept: "application/json",
          },
        });
        setData((prevData) => [...prevData, ...data.data.results]); // we are going to add the new data to current data.
        setLoading(false);
      };

      // useEffecte for invoking the function at the start
      useEffect(() => {
        fetchMovie();
      }, [page]);

      return (
        <div className="App">
          <header className="App-header">
            Popular movies according to Tmdb
            <div className="movieCardContainer">
              {data.length > 1 &&
                data.map((item) => {
                  return (
                    <MovieCard
                      key={item.id}
                      title={item.original_title}
                      description={item.overview}
                      rating={item.vote_average}
                      imageURL={item.poster_path}
                    />
                  );
                })}
              {loading && <h1>Loading....</h1>}
            </div>
          </header>
        </div>
      );
    }

    export default App;

您几乎可以理解代码,我们在其中获取数据并将其作为道具传递到 MovieCard 组件中。

创建一个 MovieCard.js 组件来显示每部电影的信息。

MoveCard.js

    import React from "react";

    export const MovieCard = ({ title, description, imageURL, rating }) => {

      const imagePath = `https://image.tmdb.org/t/p/w500${imageURL}`; // poster image path URL 

      return (
        <div className="movieCard">
          <img src={imagePath} height={400} />
          <div className="movieInfo">
            <h3>{title}</h3>
            <p>{description}</p>
            <p>{rating.toFixed(1)}⭐</p>
          </div>
        </div>
      );
    };

这是应用程序的 CSS:

App.css

    .App {
      text-align: center;
    }

    .App-header {
      background-color: #282c34;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding-top: 1em;
      font-size: calc(10px + 2vmin);
      color: white;
    }

    .movieCardContainer{
      margin-top: 1em;
      display: flex;
      flex-direction: column;
      gap: 1em;
      width: 60%;
      max-width: 800px;
    }

    .movieCard{
      display: flex;
    }

    .movieInfo{
      margin-left: 1em;
      text-align: left;
    }

    p{
      font-size: 18px;
    }

无限滚动

现在,让我们首先了解如何构建无限滚动。为此,我们将查看滚动条的位置。当滚动条位置正好位于页面末尾上方时,我们将把加载状态设置为true。

我们将有另一个 useEffect ,它会将页面状态增加 1。一旦更新页码,将触发将该页面作为依赖项的初始 useEffect。这将调用 fetchMovie() 函数来获取数据。

将事件监听器添加到滚动

首先,我们将添加甚至监听以了解滚动条位置何时更改。

    window.addEventListener("scroll", handleScroll);

处理滚动

当滚动发生时,我们将检查滚动条的当前位置是否位于网页底部的正上方(即总垂直滚动区域)。如果是,那么我们将加载状态更改为 true。

    const handleScroll = () => {
      if (document.body.scrollHeight - 300 < window.scrollY + window.innerHeight) {
        setLoading(true);
      }
    };
  • scrollHeight :该属性返回内容的总高度,包括屏幕上不可见的部分。因此,它将是总的可滚动区域。
  • scrollY:返回文档从顶部垂直滚动的像素数的属性。所以这将是已滚动的区域。
  • innerHeight:返回浏览器Windows内容区域高度的属性。它将是滚动条的宽度。它被添加到scrollY,以便当我们到达内容时而不是当我们传递内容时发生获取。 ## useEffect

成功更改加载状态后,我们可以实现 useEffect 来增加页码。这样,就可以获取电影数据了。

    useEffect(() => {
      if (loading == true) {
        setPage((prevPage) => prevPage + 1);
      }
    }, [loading]);

    // other useEffect that we already implemented

    useEffect(() => {
      fetchMovie();
    }, [page]);

优化事件监听器

由于scroll在滚动时会多次触发handleScroll,因此会导致多次不必要的函数调用。我们可以给函数添加去抖功能,这样在调用函数之前就需要一些时间。

    // debounce function
    function debounce(func, delay) {
      let timeoutId;
      return function (...args) {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
        timeoutId = setTimeout(() => {
          func(...args);
        }, delay);
      };
    }

    // adding debounce to the eventListner
    window.addEventListener("scroll", debounce(handleScroll, 500));

这是App.js的完整代码:

    import "./App.css";
    import { useState, useEffect } from "react";
    import axios from "axios";
    import { MovieCard } from "./MovieCard";

    function App() {
      const [page, setPage] = useState(1);
      const [data, setData] = useState([]);
      const [loading, setLoading] = useState(false);
      const fetchMovie = async () => {

        const URL = `https://api.themoviedb.org/3/movie/popular?language=en-US&page=${page}`;
        const data = await axios.get(URL, {
          headers: {
            Authorization:
              "Bearer API KEY",
            Accept: "application/json",
          },
        });
        setData((prevData) => [...prevData, ...data.data.results]);
        setLoading(false);
      };
      useEffect(() => {
        fetchMovie();
      }, [page]);

      const handleScroll = () => {
        if (
          document.body.scrollHeight - 300 <
          window.scrollY + window.innerHeight
        ) {
          setLoading(true);
        }
      };

      function debounce(func, delay) {
        let timeoutId;
        return function (...args) {
          if (timeoutId) {
            clearTimeout(timeoutId);
          }
          timeoutId = setTimeout(() => {
            func(...args);
          }, delay);
        };
      }

      window.addEventListener("scroll", debounce(handleScroll, 500));

      useEffect(() => {
        if (loading == true) {
          setPage((prevPage) => prevPage + 1);
        }
      }, [loading]);

      return (
        <div className="App">
          <header className="App-header">
            Popular movies according to Tmdb
            <div className="movieCardContainer">
              {data.length > 1 &&
                data.map((item) => {
                  return (
                    <MovieCard
                      key={item.id}
                      title={item.original_title}
                      description={item.overview}
                      rating={item.vote_average}
                      imageURL={item.poster_path}
                    />
                  );
                })}
              {loading && <h1>Loading....</h1>}
            </div>
          </header>
        </div>
      );
    }

    export default App;

这是演示应用程序工作原理的 GIF。

Building an Infinite Scroll Component in React

结论

在 React 中构建无限滚动组件可能是一次非常有益的体验。它不仅可以增强您对滚动工作原理的理解,还可以教您有关状态管理、事件侦听器和去抖等优化技术的知识。通过遵循本指南,您现在拥有了基本的无限滚动设置,您可以根据需要进行自定义和改进。

无论您是显示电影数据、博客文章还是任何其他内容,此组件都是坚实的基础。请记住,关键是通过仔细管理用户滚动时获取数据的时间和方式来确保流畅的用户体验。快乐编码!

以上是在 React 中构建无限滚动组件的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn