Infinity scroll을 위한 여정

MM·2022년 12월 25일

make it worth

목록 보기
2/10
post-thumbnail

하지만 날로 먹지 못했다. 몇 시간의 삽질 끝에야 먹었다.
공식 문서를 잘 읽자...

😰 무한 스크롤을 찾아 떠난 이유

NextJS에서는 if없이 window를 찾지 못한다

window객체는 클라이언트 사이드 측 렌더링이 진행될 때 만들어지기 때문에!!
서버사이드 렌더링을 우선하는 nextjs에서는 window에 접근하지 못했던 것...

접근방법은 두 가지였고, 아래 각각의 이유로 window 직접 접근을 포기했다.

if(window) {
  //1.if문으로 존재 체크 후 window에 접근하기
  //하지만 스크롤 체크가 window생성 이후 진행된다는 보장이 없다!
  //스크롤 체크만을 위해 async/await을 쓰는 것도 지나치다!
}

useEffect(()=>{
	//2.클라이언트 사이드에서의 진행이 보장되는 useEffect안에서 접근
}, [
  //뭘 보고...체크할 건데요?
]);

시도1. framer-motion

노마드코더 수업때 쓰던 방법.

window의 스크롤에 직접 접근하는 방법 대신 두 번째로 택한 것이 노마드코더 수업 때 사용했던 framer-motion이었다.
단, 그때와는 버전 차이로 인해 직접 문서를 읽으면서 적용했다.


  const { scrollY } = useScroll();
  const [scroll, setScroll] = useState(null);

  useEffect(() => {
    return scrollY.onChange((latest) => {
       setScroll(latest);
    })
  }, []);

🤔 꼭 scroll을 변화할 때마다 값을 확인해야 할까?

우리가 원하는 건 scroll이 바닥을 찍었느냐 아니냐일 뿐이지, 상세한 스크롤 값은 필요가 없는데....
좀 더 효율적인 방식이 있을 것 같아 다른 방법을 찾아보았다.

시도2. observer

entries를 잘 써야 했습니다!!

공식 문서 번역이 이해가 안 되어서 잘 해석해 둔 블로그 글을 가져왔다.
https://heropy.blog/2019/10/27/intersection-observer/https://velog.io/@silverj-kim/무한스크롤-intersection-observer

공식문서의 예시와 위 블로그에서 번역한 옵션들을 사용하여… 드디어 인식에 성공했다.

infinite query와 조합하여 사용했다.

const {
    data: StoreQueryDatas,
    fetchNextPage,
    hasNextPage,
    isFetching: StoreQueryFetching,
    isLoading: StoreQueryLoading,
  } = useInfiniteQuery({
    queryKey: ["store", nowCategory],
    queryFn: ({ pageParam = 1 }) =>
      fetchStoresData({ nowCategory: nowCategory, page: pageParam }),
    getNextPageParam: (NowPage, pages) => {
      console.log("다음페이지:", NowPage.currentPage + 1);
      if (NowPage.next) return NowPage.currentPage + 1;
      else return null;
    },
    retry: 0,
    refetchOnWindowFocus: false,
  });

const storeRef = useRef(null);
  let io = null;
  const [throttle, setThrottle] = useState(true);
  const throttling = () => {
    console.log("스크롤 콕", throttle);
    if (throttle) {
      setThrottle(false);
      setTimeout(() => {
        console.log("새 정보");
        fetchNextPage();
      }, 100);
      setThrottle(true);
    }
  };

  useEffect(() => {
    io = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) throttling();
      });
    });
    io.observe(storeRef.current);
  }, [StoreQueryDatas]);

😌 디바운싱보다 쓰로틀링

처음엔 당연히 여러 번 찍는 것중 한 번만 인식해야 하니 디바운싱이겠지?했는데...
디바운싱보다 쓰로틀링 쪽이 좀 더 자연스러운 무한 스크롤 진행이 가능하다고 한다!

해당 방식을 이용하여 무한 스크롤을 적용할 수 있었으나..
....길다! 코드가 지나치게 길다.
쓰로틀링을 아예 사용하지 않는 방법도 있지 않을까? 하고 찾아본 결과.

시도3. useInView 훅 사용하기

react측에서 observer를 이용하여 만든 훅이 있다고 한다! 즉시 사용했다.
사용 동작원리는 observer와 크게 다르지 않았다.
거기에 현재 무한 스크롤링과 함께 사용중인 인피니트 쿼리를 도입하여 함께 사용했다.

const { data, fetchNextPage, isFetchingNextPage, isLoading } =
    useInfiniteQuery({
      queryKey: "bamboo",
      queryFn: ({ pageParam = 1 }) => fetchBambooList(pageParam),
      getNextPageParam: NowPage => {
        if (NowPage.next) return NowPage.currentPage + 1;
      },
      retry: 0,
      refetchOnWindowFocus: false,
    });
  const [ref, inView] = useInView();

  useEffect(() => {
    if (inView) fetchNextPage();
  }, [inView]);
profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글