💙 React

[REACT] Infinite scroll (무한스크롤) 구현하기

Eun_zii 2023. 10. 13. 14:21

 

기존에 NodeJS로 만들어둔 서버에서 데이터를 get 해와서 프론트에서 라이브러리를 사용하지 않고 직접 무한스크롤을 구현해보았다.

예전에 해봤던건데 다시 하려니 헷갈리기 시작 ...😵‍💫 ; 그래도 어찌어찌 구현은 해보았다 .. 

스크롤이 움직이면 데이터를 계속 해서 불러온다.

( + 스크롤이 바닥에 닿으면 데이터를 불러오는 코드도 구현예정)

 

// useGetFruits.ts
import axios from "axios";
import { useInfiniteQuery } from "react-query";

const fetchFruits = async () => {
  const { data } = await axios.get(`http://localhost:8080/fruits`);
  return data;
};

const useGetFruits = () => {
  return useInfiniteQuery("fruits", fetchFruits, {
    getNextPageParam: (lastPage, allPages) => {
      if (lastPage.length > 0) return undefined;
      return allPages.length + 1;
    },
  });
};

export default useGetFruits;

 

// Main.tsx

import { useCallback, useEffect, useRef, useState } from "react";
import styled from "styled-components";

import useGetFruits from "src/api/useGetFruits";
import Fruit from "src/templates/Fruit";
import { FruitType } from "src/types/Fruit";

const Main = () => {
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useGetFruits();
  const [loadData, setLoadData] = useState(false);
  const ref = useRef<any>(null);

  const handleScroll = useCallback(() => {
    const { clientHeight, scrollTop, scrollHeight } = ref.current;
    if (
      clientHeight + scrollTop >= scrollHeight - 1 &&
      hasNextPage &&
      !isFetchingNextPage
    ) {
      setLoadData(true);
    }
  }, [hasNextPage, isFetchingNextPage]);

  useEffect(() => {
    if (loadData) {
      fetchNextPage();
      setLoadData(false);
    }
  }, [loadData, fetchNextPage]);

  useEffect(() => {
    if (ref.current) {
      window.addEventListener("scroll", handleScroll, true);
    }

    return () => {
      if (ref.current) {
        window.removeEventListener("scroll", handleScroll, true);
      }
    };
  }, [handleScroll]);

  return (
    <Container>
      <Title>🍏 Infinite_Scroll 🍏</Title>
      <List ref={ref}>
        {data &&
          data.pages.map((pageData) =>
            Array.isArray(pageData)
              ? pageData.map((fruit: FruitType) => (
                  <Fruit key={fruit.id} fruit={fruit} />
                ))
              : null
          )}
      </List>
    </Container>
  );
};

const Container = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  text-align: center;
`;

const Title = styled.h2`
  font-size: 50px;
`;

const List = styled.div`
  margin: 20px 0 0;
  font-size: 35px;
`;

export default Main;

 

728x90
댓글수0