스크롤 위치 원래 이렇게 어중간해요?

jinew·2025년 2월 24일

🚀 트러블슈팅

목록 보기
12/16
post-thumbnail

🚨 이슈 사항


  • 이슈 내용: React로 구현된 웹 애플리케이션에서 페이지를 이동했을 때 스크롤 위치가 초기화되지 않고 이전 페이지의 스크롤 위치가 그대로 반영되는 이슈



1. 사건의 발단

: 배포된 페이지를 QA 할 겸 주변 지인들에게 공유했다. 퍼블리셔 시절 옆에서 많이 가르쳐주셨던 사수분께도 전달드리며 "팀장님~ 제가 이제 리액트도 할 줄 알아요~" 하고 보내놓고 뿌듯해 했는데 돌아온 답장

👩‍💼 : 이거 페이지 이동하면 스크롤 위치 원래 이렇게 어중간해요?

어어,, 얘가 왜이럴까 정말 당황하게되. 퇴사를 해도 사수님의 피드백은 손이 벌벌 떨렸다네요

이슈 상황을 묘사해보자면 홈 화면에서 아래쪽에 위치한 '내 MBTI 알아보러 가기' 버튼을 클릭하면 검사 페이지로 이동하는데, 이 때 1번 문항이 아닌 2~3번 문항부터 보인다는 거다.

즉, 이전 페이지에서 사용자가 보던 스크롤 위치가 그대로 유지되는 문제였다.


2. 고민하기

: 이 이슈에 대해서 스스로 내린 결론은 '리액트가 SPA이기 때문에' 였다.

  • 일반적인 웹사이트는 페이지가 변경될 때 새로운 HTML 파일을 불러오면서 스크롤이 초기화된다.
  • 하지만 React는 SPA이기 때문에 index.html 파일이 유지된 채 라우팅만 변경된다. 즉, 스크롤 위치도 변경되지 않고 그대로 유지될 가능성이 높다.
  • 리액트 라우터는 URL을 변경해주는 역할일 뿐, 물리적인 페이지 전환이 아니기 때문에 브라우저의 기본적인 스크롤 동작이 적용되지 않는 것 같다고 판단했다.

이를 해결하기 위해 찾아보던 중 React Router DOM에서 제공하는 ScrollRestoration을 사용해보기로 했다.



3. 1차 시도 : ScrollRestoration 사용

import { ScrollRestoration } from 'react-router-dom';

const Login = () => {

  return (
    <>
      <ScrollRestoration />
      <div className="flex flex-col justify-center flex-1 min-h-full px-6 py-28 lg:px-8 ">
		...
      </div>
    </>
  );
};

하지만 처참히 실패 ..~

Uncaught Error: useMatches must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.

위 에러만 한 바가지로 떴다. 일단 왜 안 되는지부터 찾아보자..

❌ 실패 원인 분석

  1. ScrollRestoration데이터 라우터(Data Router)에서만 동작한다.

    • React Router v6에서 ScrollRestoration은 데이터 기반 라우터에서만 정상적으로 동작하도록 설계되었다.

    • 그런데 내가 사용한 라우터는 createBrowserRouter가 아닌 BrowserRouter 기반의 일반적인 라우터라서 ScrollRestoration이 제대로 적용되지 않았던 거다.

  2. ScrollRestoration기본적으로 브라우저의 history.scrollRestoration 을 조작하는 방식이다.

    • 이 설정은 브라우저가 페이지 이동 시 스크롤 상태를 복원할지 여부를 제어하는데 사용된다.
    • 하지만 React의 SPA 환경에서는 '새로운 페이지'가 아니라 '컴포넌트만 교체'되는 방식이라, 우리가 원하는대로 동작하지 않을 수 있다.

4. 2차 시도 : useEffect를 활용한 방법

: 위 방법이 실패해서 다른 방법을 찾아보다가 페이지 이동 시 useEffect를 사용하여 스크롤을 강제로 맨 위로 끌어올리는 방법을 알게 됐다.

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

const ScrollToTop = () => {
  const location = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0); // 페이지 이동 시 스크롤을 맨 위로 초기화
  }, [location]);

  return null;
};

export default ScrollToTop;

: 그리고 이 ScrollToTop 컴포넌트를 라우터 내부에서 사용한다.

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import ScrollToTop from '../components/ScrollToTop';
import Home from '../pages/Home';
import TestPage from '../pages/TestPage';

const Router = () => {
  return (
    <BrowserRouter>
      <ScrollToTop />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/test" element={<TestPage />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

결과는 ..~?




✅ 해결!


: 드디어 .. 페이지가 이동할 때마다 스크롤이 맨 위로 초기화된다!


📑 정리

  • React는 SPA이므로 페이지 이동 시 스크롤이 초기화되지 않는다.
  • React Router의 ScrollRestoration은 Data Router에서만 동작하기 때문에 Brower Router로 구현된 이번 프로젝트에서는 사용이 불가하다.
  • useEffect 를 활용하여 window.scrollTo(0, 0)을 실행하면 스크롤을 초기화할 수 있다!
profile
멈추지만 않으면 도착해 🛫

0개의 댓글