💙 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