본문 바로가기

React

React 스크롤 페이징 구현 react-intersection-observer

728x90

리액트 프로젝트 개발을 하면서 목록에서 스크롤 페이징 개발 중 이슈가 생겼다.

 

const [shopList, setShopList] = useState([]);

const scrollHandle = () => {
    let scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
    let clientHeight = document.documentElement.clientHeight;
    let scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
    
    if((scrollTop + clientHeight) > scrollHeight){	//스크롤이 마지막이면
      let paging = {...shop, offset : shop.offset + 9};
      getShopList(paging).then(res => {
        if(res.status == 200){
          setShopList([...shopList, ...res.data]);
          
        }
      })
      setShop({...shop, offset : (shop.offset + 9)});

    }
  }

useEffect(() => {
    getShopList(shop).then(res => {
        onLoading();
        if(res.status == 200){
          setShopList(res.data);
        } else {
            console.log(res.status);
        }
        offLoading();
    })
    

    window.addEventListener("scroll", scrollHandle);
    return () => window.removeEventListener("scroll", scrollHandle);

  }, [블라 블라]);

shopList가 목록 페이지에 뿌려지고 있었기 때문에 스크롤 이벤트를 윈도우에 추가하고

스크롤 마지막인 경우를 체크해서 기존 shopList에 추가로 가져온 res.data를 붙이면 되겠다 생각을 했지만

 

예상하지 못했던 부분에 이슈가 발생했다.

스크롤이 마지막에 닿으면 목록에 있던 기존데이터가 삭제되고 새로 가져온 데이터만 뿌려지는 이슈였는데

scrollHandle을 정의할때 사용된 ...shopList가 빈 데이터였기 때문이다.

 

useEffect에서 shopList를 가져오기 전에 scrollHandle을 정의했고 그 땐 데이터가 비어져있던게 이유인듯 싶었다.

 

그래서 대안을 검색하던중 알게된 react-intersection-observer를 사용하는 방법이 있었다.

 

npm install react-intersection-observer

설치

 

import { useInView } from 'react-intersection-observer';

리스트 페이지에 임포트 해준 후

 

useInView로 ref 변수를 정의했다.

const [last, inView] = useInView();

 

 

return에서 목록 데이터중 마지막인 경우 ref를 추가해주었다.

shopList.map((shop, index) => (
	<React.Fragment key={index}>
		{
			shopList.length-1 == index?
				<Grid item key={shop} xs={12} sm={6} md={4} ref={last}>

 

마지막 데이터 즉, last를 ref로 정의한 데이터가 페이지에 보여지는경우에 inView에 true 값이 들어간다. (처음엔 false)

때문에 inView값이 바뀔때 데이터를 가져와 붙여주는 로직을 정의하면 된다. => useEffect({},[inView])

 

 

useEffect 추가

const moreCnt = 9;
const [more, setMore] = useState(true);
  
useEffect(() => {
    if(more){
      getShopList(shop).then(res => {
        if(res.status == 200){
            setShopList([...shopList, ...res.data]);  
            if(res.data.length < moreCnt){
              setMore(false);
            }
        }
      })
      setShop({...shop, offset : (shop.offset + moreCnt)});
    }
  }, [inView])

스크롤 페이징에 사용할 변수 moreCnt(더 가져올 수)와 조건값으로 사용해줄 more을 정의하고

useEffect를 추가해주었다.

[inView]가 되어있기 때문에 inView 값이 바뀔때마다 useEffect가 실행이 되고,

more가 true인 경우만 데이터를 추가적으로 가져오도록 개발했다.

 

추가로 가져온 데이터가 더 가져올 moreCnt보다 적으면 더이상 데이터가 없기 때문에 more을 false로 setState해준다.

 

728x90