[React] 페이지 이동/뒤로가기 시 스크롤 위치 복원 (SPA, React Router, sessionStorage)

junhyung kwon·2025년 7월 24일
0

SPA(Single Page Application) 환경에서 React Router를 쓸 때,

  • 상세 페이지 → 목록으로 뒤로가기를 눌러도
  • 항상 맨 위(0, 0)에서 시작하는 불편한 경험이 다들 있으실거에요!

실제 서비스 UX에서는
"이전 위치로 자연스럽게 스크롤이 복원"되어야 사용성이 좋아집니다.


✨ 구현 원리

  1. 페이지를 떠날 때
    • 현재 경로(path)와 스크롤 위치(window.scrollY)를
      sessionStorage에 저장합니다.
  2. 뒤로가기/앞으로가기(POP) 시
    • 해당 경로의 저장된 스크롤 위치로
      window.scrollTo(0, 저장된값)으로 이동합니다.

🧑‍💻 핵심 코드 (Copy & Paste!)

아래 컴포넌트를 App.js 등 라우터 바로 아래에 추가하면 끝!

import { useEffect, useLayoutEffect, useRef } from 'react';
import { useLocation, useNavigationType } from 'react-router-dom';

export default function ScrollRestoration() {
  const { pathname } = useLocation();
  const navType = useNavigationType();
  const prevPathRef = useRef(pathname);
  const scrollYRef = useRef(0);

  // 1. 현재 스크롤 위치 추적
  useEffect(() => {
    const saveScroll = () => { scrollYRef.current = window.scrollY; };
    window.addEventListener('scroll', saveScroll);
    return () => window.removeEventListener('scroll', saveScroll);
  }, []);

  useLayoutEffect(() => {
    // 페이지 이동(PUSH)할 때: 떠나는 페이지 위치 저장
    if (navType === 'PUSH') {
      const prevPath = prevPathRef.current;
      if (prevPath !== pathname) {
        sessionStorage.setItem(`scroll_${prevPath}`, scrollYRef.current);
      }
      window.scrollTo(0, 0);
    }
    // 뒤로가기(POP) 할 때: 저장된 위치로 복원 (여러 번 시도)
    else if (navType === 'POP') {
      const saved = Number(sessionStorage.getItem(`scroll_${pathname}`)) || 0;
      let tries = 0;
      const restore = () => {
        window.scrollTo(0, saved);
        if (window.scrollY !== saved && tries++ < 5) setTimeout(restore, 100);
      };
      restore();
    }
    prevPathRef.current = pathname;
  }, [pathname, navType]);

  return null;
}


---

## ⚡️ 실전 적용 방법

1. `ScrollRestoration` 컴포넌트를 **App.js** 등 라우터 바로 아래에 추가
2. 페이지 간 이동/뒤로가기 UX가 한 단계 업그레이드!

---

## 🛠️ 실전에서 겪은 팁

- 데이터 렌더링이 느리면 스크롤 복원이 안 될 수 있는데,
  여러 번 시도(`setTimeout`)로 자연스럽게 해결!
- header가 fixed일 때는 scroll 위치에서 header 높이만큼 빼주면 된다.

---

## ✅ 마치며

이 패턴 하나로  
사용자가 "다시 보기 편한" SPA를 만들 수 있습니다!  
궁금한 점, 확장 아이디어는 댓글 환영합니다 :)
profile
“Everything comes to him who hustles while he waits” 항상 최고가 되기 위해 꾸준히 노력하며 성장해 나아가는 Front-End 개발자 권준형입니다.

0개의 댓글