Nextjs야 Scroll Restoration 된다며

·2023년 5월 8일
0

삽질LOG

목록 보기
7/13

내가 이 회사 와서 제일 처음 구현한게 바로 scroll restore 기능이다. custom hook으로 제작했으며..개발 과정에 있던 내 삽질 과정을 적어보려고 한다.

삽질의 시작

분명 공식문서에는 Nextjs가 scroll restoration을 지원한다고 적혀있다. 근데 공식문서에서 하라는 그대로~ 해도 안됐다. 왜인지는 아직도 모르겠다. 구글링해서 나오는 각종 방법도 써봤는데 되는 페이지가 있고 안되는 페이지가 있고 아주 각양각색이었다. 아시는 분 있으시면 제발 누가 알려주면 좋겠다.

그래서 난 이렇게 했었다.

저번 회사에서도 같은 기능을 만들었던 적이 있다. 그 당시엔

  1. 페이지 이동이 일어났을 때 local storage에 아래 형태로 저장
{ url: { ..., scrollY: 689 } }
  1. useEffect에서 local storage를 확인하고 현재 url이 key로 저장되어있으면 스크롤을 이동시킨다.

구현도 간단했고 스크롤 복원 이라는 표면적인 것에만 초점을 맞춘다면 상당히 잘 동작했다. 하지만 문제가 있었다. 뒤로가기 시에만 스크롤이 복원되어야하는데 아니여도 이전 스크롤이 복원된다는 것이었다.

보여줄께 이전보다 발전한 나

이번엔 만들면서 저번보다 두가지를 개선하고싶었다.

  1. 모든 사람이 쉽게 가져다 쓰게 하고 싶다. (이전 회사는 나 혼자 북치고 장구치고 다 하는 곳이라 이런 고민이 좀 덜 필요했다.)
  2. 뒤로가기를 했을 때만 스크롤을 복원하고싶다.

local storage는 동일하게 사용해도 됐을 것 같지만 이번 회사에선 redux를 사용하고 있어서 store에 저장해서 쓰기로 했다.

단계별로 발전했어요.

1단계
처음에는 직전 뒤로 가기만 생각해서 만들었다. 그래서 redux store에도 scroll을 그냥 한번만 저장하고 날렸다.
routeChangeStart 이벤트가 발생했을 때 스크롤 정보를 저장하고
routeChangeComplete 이벤트가 발생하면 스크롤을 복원했다.

2단계
하지만 홈 => 제품 목록 => 제품 => 제품 브랜드 이런식으로 스크롤 히스토리가 쌓이는 경우 뒤로 갈 때마다 스크롤 복원이 필요해서 store에서 스택처럼 pop, push를 진행했다.

3단계
라우터 이동 시마다 스크롤을 위치를 저장했더니 뒤로가기를 눌렀을 때도 스크롤이 불필요하게 저장되었다. 그래서 shouldSaveScroll 이라는 변수를 하나 추가해서 popState가 아닐 때만 스크롤 상태를 저장했다.

완성된 코드 일부를 보면 아래와 같다!


...

  useEffect(() => {
    if (!"scrollRestoration" in window.history) return;

    let shouldSaveScroll = true;
    window.history.scrollRestoration = "manual";

    const onRouteChangeStart = () => {
      if (!shouldSaveScroll) return;
      saveScrollPos(); // 
    };

    const onRouteChangeComplete = () => {
      restoreScrollPos();
    };

    Router.beforePopState(() => {
      shouldSaveScroll = false;
      return true;
    });
    Router.events.on("routeChangeStart", onRouteChangeStart);
    Router.events.on("routeChangeComplete", onRouteChangeComplete);

    return () => {
      Router.beforePopState(() => true);
      Router.events.off("routeChangeStart", onRouteChangeStart);
      Router.events.off("routeChangeComplete", onRouteChangeComplete);
    };
  }, [router]);

...

소감

확실히 이전 회사에서 구현했던 방식보다 더 나은 방법인 것 같다. 그땐 라우터 이벤트도 활용하지 못 했는데 이번에는 확실하게 활용할 수 있었다. 아직도 쪼랩이지만 조금은 덜 쪼랩이된것 같아 기뿌다.

참고자료

https://nextjs.org/docs/api-reference/next/router#routerevents

profile
이제는 병아리는 벗어나야하는 프론트개발자

0개의 댓글