[React] 스크롤시 등장/퇴장 애니메이션 효과 적용해보기 (feat. framer motion & react-intersection-observer)

2022. 9. 3. 12:46React

728x90

이번 포스트에서는 스크롤을 내려 특정 요소가 화면에 보일 때 자연스러운 애니메이션 효과가 날 수 있도록 구현해보도록 하겠습니다.

 

 

적용된 애니메이션

 

사용할 패키지는 애니메이션을 선언형으로 손쉽게, 그리고 직관적으로 구성할 수 있도록 해주는 framer-motion 그리고 특정 요소가 화면에 들어왔는지 감지할 수 있도록 해주는 react-intersection-observer 입니다.

 

react-intersection-observer는 아래 포스트에서 무한 스크롤을 구현하기 위해 사용했던 intersection observer의 api를 react에서 훅 형태로 쉽게 관리하고 사용할 수 있도록 만든 패키지이기 때문에 그냥 직접 구현해서 사용해도 되지만 최대한 효율적이면서 손쉽게 구현하기 위해 사용해보도록 하겠습니다.

 

 

[Firebase] 파이어스토어 페이지네이션 + 무한 스크롤 구현하기 (feat. React)

애플리케이션을 만들 때 매번 전체 문서를 반환하도록 로직을 짜게 되면 규모가 커질수록 수백 또는 수천 개의 고비용 쿼리가 발생하기 때문에 정해진 수의 결과만 반환하도록 별도의 처리를

mingeesuh.tistory.com

 

npm i framer-motion react-intersection-observer

 

 


1. 화면에 요소가 보일 때 애니메이션을 적용하는 커스텀 훅 작성

우선 화면에 요소가 보일때 애니메이션이 동작할 수 있도록 커스텀 훅을 작성해보도록 하겠습니다.

// hooks/useObserver

import { useEffect } from "react";
import { useAnimation } = from "framer-motion";
import { useInView } from "react-intersection-observer";

const useObserver = () => {
  const animation = useAnimation();
  const { ref, inView } = useInView();

  useEffect(() => {
    if (inView) {
      animation.start("visible");
    } else {
      animation.start("hidden");
    }
  }, [animation, inView]);

  return { ref, animation };
};

export default useObserver;

위와 같이 react-intersection-observer의 useInView 훅을 사용하면 참조값(ref)과 해당 참조를 가진 요소가 화면에 보이는지에 대한 여부를 나타내는 boolean값인 inView를 반환받을 수 있습니다.

 

그 후, framer-motion의 useAnimation 훅을 통해 애니메이션을 트리거할 수 있는 객체를 생성 후 inView값에 따라 적용할 애니메이션 이름을 start 메서드의 인자로 넣어주시면  됩니다. 

 

위에 예제에서는 화면에 보이면 visible이라는 애니메이션을 실행하고 그렇지 않다면 hidden이라는 애니메이션을 실행하도록 해두었습니다.

 


2.  애니메이션 Variants 정의

Framer motion에서 variants란 미리 정의된 컴포넌트의 비주얼 상태로서, 위에 visible이랑 hidden이라는 애니메이션이 정확히 어떤 애니메이션인지 정의해주는 단계가 필요합니다.

 

필자는 styles 폴더의 animation 파일을 별도로 만들어 사용할 variants를 그때마다 import 해서 사용하기 때문에 아래와 같이 애니메이션을 정의해두었습니다. 간단하게 투명도만 조절해보겠습니다.

 

// styles/animation.js

export const opacityVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      duration: 1,
    },
  },
};
``;

 

3. 사용하기

이제 사용할 페이지에서 useObserver 커스텀 훅 실행 후 반환받은 ref를 전달해주기만 하면 됩니다. framer-motion으로 애니메이션을 적용할 때는 꼭 아래 예제와 같이 일반 태그가 아닌 motion에서 제공하는 태그를 사용해주시길 바랍니다.

 

import { opacityVariants } from "styles/animation";

const App = () => {
const { ref, animation } = useObserver();
// 생략

// 애니메이션 적용할 컴포넌트
<motion.div 
    ref={ref}
    initial="hidden"
    animate={animation}
    variants={opacityVariants}
>
 // 생략    
</motion.div>
}

 

위와 같이 초기 상태의 값을 motion.div의 inital prop 그리고 useObserver 커스텀 훅에서 반환받은 animation 객체를 animate prop으로 각각 전달해주면 해당 컴포넌트가 화면에 교차할 때마다 사라졌다 보였다 하는 부드러운 애니메이션을 보실 수 있습니다. 

 

좀 더 복잡한 애니메이션을 원하시는 분들은 Framer motion 예제를 한번 살펴보시길 바랍니다.

 

이미 너무 좋은 자료들이 많이 있기 때문에 앞으로도 Framer motion에 대해서 깊게 다루지는 않을 예정이지만 좀 더 자세한 설명이 필요하신분들은 댓글을 남겨주시면 짧게나마 만들어보도록 하겠습니다.