[IntersectionObserver] fade-in 애니메이션 구현 중 이슈 해결하기

Sheryl Yun·2024년 1월 25일
0
post-thumbnail

시간차를 두고 떠오르는 텍스트 애니메이션을 컴포넌트가 스크롤을 통해 뷰포트에 들어왔을 때 실행시키고자 IntersectionObserver를 적용했다.

적용 자체는 어렵지 않았는데 적용하는 과정에서 해결하고 싶은 이슈들이 추가로 생겨났다.

  1. 화면을 새로고침했을 때 화면 최상단으로 스크롤 이동하기
  2. 스크롤을 내리면서 한번 애니메이션이 보여지고 난 뒤 스크롤을 올리면 해당 텍스트 애니메이션이 재실행되지 않게 하기
  3. 기사이트 첫 진입 시 '/' 경로가 아닌 '/technology'로 자동 redirect 하기

3번 이슈의 경우 처음에 만든 ScrollToTop 컴포넌트가 페이지가 이동할 때 useEffect에서 pathname 변경 여부를 감지하고자 useLocation을 썼는데 이 때문인지 ScrollToTop 컴포넌트를 App에 넣을 때 Router 문맥이 필요하다는 에러가 떴다.

어차피 나중에 Service 페이지도 만들 예정이어서 Technology 컴포넌트들을 미리 pages 폴더에 분리할 겸 생각해본 이슈였다. (1, 2번은 UX 관련 이슈라서 꼭 해결해야 했고..) 어쨌든 첫 번째 이슈부터 차근차근 해결하기 시작했다.

1. 화면을 새로고침했을 때 화면 최상단으로 스크롤 이동시키기

처음에 시도한 코드는 App에 넣어도 page에 넣어도 동작하지 않았다.

  useEffect(() => {
      window.scrollTo(0, 0);
  }, []);

더 찾아본 코드는 onbeforeunload가 들어간 코드였는데 이건 잘 동작했다.

  useEffect(() => {
    window.onbeforeunload = function () {
      window.scrollTo(0, 0);
    };
  }, []);

onbeforeunload사용자가 '페이지를 떠날 때' 해당 페이지 내에서 변경된 값들을 다시 기존의 값으로 초기화하는 이벤트였다.

[ 다음과 같은 경우에 적용 ]

  • 새로고침
  • 뒤로 가기
  • 브라우저 닫기
  • form submit 등

(참고 자료: https://jaimemin.tistory.com/1539)

2. 한번 애니메이션이 보여진 후 다시 뷰포트에 들어왔을 때 애니메이션 재실행 막기

클론 중인 사이트는 스크롤을 다시 올렸을 때 애니메이션이 재실행되지 않았다. 작업 중인 localhost 화면에서도 스크롤을 다시 올렸을 때 시간차 있는 애니메이션이 위에서부터 다시 실행되는 것은 이상하게 느껴졌다.

그래서 IntersectionObserver 기능 중 observer가 '한번만 실행'되고 이후는 실행되지 않도록 하는 것을 찾아보니 'unobserve'라는 메서드가 있었다.

원래 IntersectionObserver 코드에서 if (entry.isIntersecting)의 else문을 지우고 isIntersecting 중일 때 true로 바꿈과 동시에 unobserve로 관찰을 중지했다.

  useEffect(() => {
    // 요소가 아직 준비되지 않은 경우 중단
    if (!scrollRef.current) return;

    const callback = (entries: IntersectionObserverEntry[]) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // 요소가 뷰포트에 나타난 경우
          setIsInViewport(true);
          observer.unobserve(entry.target); // 이 코드 추가
        }
        // else { // 이 코드는 삭제함
        //   setIsInViewport(false);
        // }
      });
    };

    const observer = new IntersectionObserver(callback, {
      root: null,
      rootMargin: '0px', // 참고: rootMargin에 'px'을 안 넣었더니 에러 발생
      threshold: 0,
    });

    // 요소 관찰 시작
    observer.observe(scrollRef.current);

    // 컴포넌트가 언마운트되면 관찰 중단
    return () => {
      observer.disconnect();
    };
  }, []);

이렇게 바꿨더니 한번 애니메이션이 재생된 후 스크롤을 다시 올려도 애니메이션이 재실행되지 않았다.

(참고 자료: https://charles098.tistory.com/202)

3. 사이트 첫 진입 시 '/' 경로 대신 다른 경로('/technology')로 리다이렉트 시키기

이건 갑자기 생긴 욕심.. 사이트에 들어오자마자 우선은 technology를 먼저 보여주고 싶었다.

처음에 react-router-dom의 Redirect 컴포넌트를 썼다가
나중에 보니 v5 방법이라 v6에서 새로 도입된 Navigate 컴포넌트를 써서 해결했다.

function App() {
  return (
    <BrowserRouter>
      <ScrollToTop />
      <Header />
      <Routes>
        <Route path='/' element={<Navigate replace to='/technology' />} />
        <Route path='/technology' element={<Technology />} />
      </Routes>
    </BrowserRouter>
  );
}

Redirect 방법은 Route 컴포넌트 안에 다른 컴포넌트를 중첩하는데 Navigate 방법은 Route를 한 줄(닫기 태그: </>)로 계속 유지할 수 있어서 좋았다.

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글