>  기사  >  웹 프론트엔드  >  React에서 무한 스크롤 구성 요소 구축

React에서 무한 스크롤 구성 요소 구축

WBOY
WBOY원래의
2024-08-26 21:45:021099검색

소개

우리는 애플리케이션과 웹 페이지, 특히 스크롤만 원하는 소셜 미디어에서 무한 스크롤을 봅니다. 아무 생각 없이 스크롤하는 것은 좋지 않지만 자신만의 무한 스크롤을 만드는 것은 훌륭합니다. 개발자로서 우리는 웹서핑을 하면서 보는 컴포넌트를 재현하려고 노력해야 합니다. 일부 구성 요소를 구현할 때 더 많은 것을 배우고 기존의 틀에서 벗어나 생각하는 것이 어려울 수 있습니다.

또한 애플리케이션에 무한 스크롤을 구현하려는 경우 가이드에 따라 직접 만들 수 있습니다. 스크롤 동작을 개선하기 위해 자신만의 코드를 추가할 수 있습니다.

이 기사에서는 처음부터 무한 스크롤 구성 요소를 구축해 보겠습니다. 다음 주제를 다룰 예정입니다:

  • 환경설정
  • 구성요소 빌드
  • 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로 설정하겠습니다.

페이지 상태를 1씩 증가시키는 또 다른 useEffect가 있을 것입니다. 페이지 번호가 업데이트되면 해당 페이지를 종속성으로 갖는 초기 useEffect가 트리거됩니다. 그러면 fetchMovie() 함수가 호출되어 데이터를 가져옵니다.

스크롤에 EventListner 추가하기

먼저 스크롤바 위치가 변경되면 알 수 있도록 듣기 기능도 추가하겠습니다.

    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]);

eventListner 최적화

스크롤은 스크롤하는 동안 handlerScroll을 여러 번 실행할 수 있으므로 불필요한 함수 호출이 여러 번 발생합니다. 함수를 호출하기까지 시간이 좀 걸릴 수 있도록 함수에 디바운스를 추가할 수 있습니다.

    // 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으로 문의하세요.