호텔 앱에서 무한 스크롤링을 적용하다 보니, 이전에 선택한 상품을 기억하지 못하여 다시 스크롤을 이동하는 번거로움을 해결하기 위해, 스크롤 복원(Scroll Restoration) 기능을 구현한 커스텀 훅으로, 스크롤 복원은 사용자가 이전 페이지로 돌아갔을 때 스크롤 위치를 이전 상태로 복원해주는 기능을 구현하는 데 사용됩니다.

  1. 라이브러리 등록

    import { useCallback, useContext, useEffect, useRef } from "react";
    import { Context } from "@COMPONENTS/provider/ScrollRestoreProvider";
    import { useRouter } from "next/router";
    
  2. debounce 함수 정의

    const debounce = (callback: () => void, timeout = 100) => {
      // 콜백 함수를 디바운스 처리하는 함수를 정의합니다.
    	let timer;
    	
    	return () => {
    			clearTimeout(timer);
    			timer = setTimeout(() => {
    				callback();
    			}, timeout);
    	};
    };
    
  3. useScrollRestoration 커스텀 훅 정의

    const useScrollRestoration = () => {
    	const router = useRouter();
    	const scrollRestoreContext = useContext(Context); // 스크롤 복원 Context
    	const restoreScroll = useRef<number>(); // 스크롤 위치를 저장하는 useRef
    
    	// 스크롤 이벤트를 처리하는 콜백 함수를 디바운스 처리
    	const event = useCallback(
    		debounce(() => scrollRestoreContext.setScrollData()),
    		[],
    	);
    
    	// 스크롤 위치를 복원
    	useEffect(() => {
    		restoreScroll.current = scrollRestoreContext.getScrollData();
    
    		window.addEventListener("scroll", event); // 스크롤 이벤트 리스너를 등록
    
    		return () => {
    			window.removeEventListener("scroll", event); // 컴포넌트가 언마운트될 때, 스크롤 이벤트 리스너를 제거
    		};
    	}, [router]);
    	
    	// 스크롤 복원 데이터를 설정하는 함수를 정의
    	const setRestoreData = useCallback((data: any) => {
    		scrollRestoreContext.setRestoreData(data);
    	}, []);
    	
    	// 스크롤 복원 데이터를 가져오는 함수를 정의
    	const getRestoreData = useCallback(() => scrollRestoreContext.getRestoreData(), []);
    	
    	// 스크롤 위치를 이전 값으로 복원하는 함수를 정의
    	const scrollUpdate = useCallback(() => {
    		window.scrollTo(0, Number(restoreScroll.current));
    	}, []);
    
    	return {setRestoreData, getRestoreData, scrollUpdate};
    };
    
  4. scrollRestore 함수 정의

// 스크롤 데이터를 Context에 저장하는 로직
const scrollRestore = () => {
	const scrollRestoreContext = useContext(Context);
	
		const setRestoreData = useCallback((data: any) => {
			scrollRestoreContext.setRestoreData(data);
		}, []);
	
		const getRestoreData = useCallback(() => scrollRestoreContext.getRestoreData(), []);
	
		return {setRestoreData, getRestoreData};
};