SPA(Single Page Application) 환경에서 React Router를 쓸 때,
실제 서비스 UX에서는
"이전 위치로 자연스럽게 스크롤이 복원"되어야 사용성이 좋아집니다.
sessionStorage에 저장합니다.window.scrollTo(0, 저장된값)으로 이동합니다.아래 컴포넌트를 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를 만들 수 있습니다!
궁금한 점, 확장 아이디어는 댓글 환영합니다 :)