Skip to main content

Command Palette

Search for a command to run...

[React] Framer Motion

Updated
3 min read

오늘은 리액트의 애니메이션 라이브러리중 하나인 Framer Motion에 대해 작성해보겠다.

Framer Motion을 사용하게 된 계기는, 방학때 진행했던 CATch Mind라는 디자이너 협업 퀴즈 게임 개발을 하다가, 연속적으로 나오는 애니메이션 구현을 위해 사용했다. 예를 들어, 캐릭터가 진화하는 장면에서, 기존의 캐릭터가 화면 아래로 내려가고 새로운 캐릭터가 올라와야 했다. 마치 포켓몬스터 진화하는 장면처럼 말이다. 이를 위해서는 DOM에서 지워질때 애니메이션을 적용했어야 했는데, React가 State로 Component를 관리할 때, 즉시 DOM을 업데이트 해서, 사라질때 애니메이션 구현이 어려웠다. 이를 해결해주는 기깔난 라이브러리를 찾았는데, 그게 Framer Motion이였다.

Framer Motion 공식 사이트

https://www.framer.com/motion/

프로젝트 주소(반응형이 아니고, IPad 12Pro 기준임, 방학때 반응형으로 고칠 예정)

https://catch-project.vercel.app/


설치 및 사용 방법

  • node.js 다운로드하기 - Javscript Run time

  • npm install framer-motion

  • import {motion} from"framer-motion"

  • <motion.div> ...codes </motion.div>

    • <motion.div>를 적용시키고 싶은 JSX에 붙여주면 된다.

사용 방법

기본적으로 <motion.div>의 props로 값들을 전달해서 사용한다.

  1. animate prop

    : 적용시킬 애니메이션을 넣는 곳이다. Css 스타일에 Base를 두었다.

  2. transition prop

    : 애니메이션이 어떻게 적용될지 결정한다.

    ex) duration, ease, repeat etc

     // translatex 100 for 2 seconds in easeOut
     <motion.div
       animate={{ x: 100 }}
       transition={{ ease: "easeOut", duration: 2 }}
     />
    

    지원하는 CSS Animations

    • Translate shortcuts: x, y, z

    • Translate: translateX, translateY, translateZ

    • Scale: scale, scaleX, scaleY

    • Rotate: rotate, rotateX, rotateY, rotateZ

    • Skew: skew, skewX, skewY

    • Perspective: transformPerspective

지원하는 ValueTypes

  • Numbers: 0, 10 etc.

  • Strings containing numbers: "0vh", "10px" etc.

  • Colors: Hex, RGB, HSLA.

  • Complex strings containing multiple numbers and/or colors (ie "10px 0 #000")

  1. initial prop

    : 처음 렌더링될때 상태를 의미한다. 즉, DOM에 처음 렌더링 될때의 초기 상태를 정의해줄 수 있다.

  2. exit prop

    : 컴포넌트가 렌더링 해제(?) 즉, DOM에서 삭제될때 최종 상태를 정의할 수 있다.

    2개의 Props를 통해, 리액트의 단점인 DOM에서 컴포넌트가 삭제될때의 애니메이션을 구현할 수 있다.

     <AnimatePresence>
       // isVisible state를 통해, DOM Element를 관리한
       {isVisible && (
         // 안보임(등장전) > 보임(등장) > 안보임(퇴장)
         <motion.div
           key="modal"
           initial={{ opacity: 0 }}
           animate={{ opacity: 1 }}
           exit={{ opacity: 0 }}
         />
       )}
     </AnimatePresence>
    
    • 추가로, <AnimatePresence>라는 컴포넌트로 감싸주어야 한다.

      import { motion,AnimatePresence} from "framer-motion"

    • AnimatePresence 에는 key값을 설정해주어야 DOM Tree에서 track할 수 있다한다.

cf) 만약, animate 속성의 객체에 정의된 값과 기본 값(처음 렌더링 된 상태)이 다르면, animate가 실행된다. initial = {false}를 통해, 이를 방지할 수 있다.


그런데, 만약 여러 코드가 같은 애니메이션을 사용한다면 계속 initial, aniamte를 작성해야 할까? 귀찮다. 이를 위해서, variants 라는 기능을 제공한다. 또한, variants는 부모 자식간의 Orchestration (연속적 애니메이션 재생)을 가능하게 한다.

먼저, 기본 사용법을 알아보자.

variants라는 객체에 2개의 key값에 최초 상태, 최종 상태를 정의해주면 된다.

const variants = {
  hidden: {
    backgroundColor: "#fff",
    transition: { duration: 2 }
  },
  visible: {
      backgroundColor: "#f00"
  }
}
// 초기 : inactive 상태, 등장 후 :active 상태,
<motion.div 
    variants={variants},
    initial="hidden",
    animate="visible" />

variant의 중요한 특징은 자식이 자신만의 애니메이션을 정의하지 않으면, 자식으로 애니메이션이 전파된다는 것이다.

예제를 통해 알아보자.

const list = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

const item = {
  visible: { opacity: 1, x: 0 },
  hidden: { opacity: 0, x: -100 },
}

return (
  <motion.ul
    initial="hidden"
    animate="visible"
    variants={list}
  >
    // li 는 list variant를 상속받지만, item variant로 덮어씀
    <motion.li variants={item} />
    <motion.li variants={item} />
    <motion.li variants={item} />
  </motion.ul>
)

내가 매력적이라 느꼈던 다음 기능은, 부모 자식간 애니메이션 연속 설정(Orchestration) 기능이다. 가끔은, 부모이후에 일정시간을 두고 자식의 애니메이션을 실행했어야 했다. 이를 위해서, delay를 두고 힘들게 만들었어야 했는데, Framer-Motion은 코드 한줄로 이를 가능하게한다.

코드로 이해해보자.

 const list = {
  visible: {
    opacity: 1,
    transition: {
      when: "beforeChildren",      
    },
  },
  hidden: {
    opacity: 0,
    transition: {
      when: "afterChildren",
    },
  },
}
return (
  <motion.ul
    initial="hidden"
    animate="visible"
    variants={list}
  >
    // li 는 ul이 끝나면 자동으로 실행된다. 우와~
    <motion.li/>
    <motion.li/>
    <motion.li/>
  </motion.ul>
)

내가 썻던 기능들은 이런 것들이다. 사실 hover, scroll 등 이외에도 많은 기능이 있다. 거의 겉면만 핥은 수준이다. 다음에, 프로젝트에서 사용하게 된되면 이어서 써보겠다. 쓰지도 않을 것을 공부하는건 낭비가 아닌가!!??
edited by 김지호

More from this blog

[ZSH] tree 사용하기

들어가며 큰 규모의 프로젝트를 출시한 뒤, 후일을 위해서 더 늦기 전에 파일 정리 및 문서화를 진행해야했다. 문서화 작업을 하는 중에 기왕 정리하는 거 파일 구조를 이쁘게 트리 구조로 나열하여 코멘트를 달면 나중에 보더라도 이해하기 더 쉬울 것 같았다. 어떻게 해야 간지나는 트리 구조를 만들 수 있을까 방법을 찾다보니 역시나 파일 구조를 트리로 이쁘게 출력해주는 커맨드 툴이 존재했다. tree 커맨드에 대해서 알아보고 알짜배기 내용만 정리했다....

Feb 21, 20242 min read

[Next.js] parallel routes & intercepting routes

트위터 로그인 모달창을 만들어보며 넥스트의 parallel routes 와 intercepting routes 을 학습한 내용을 정리해보았습니다. 트위터 로그인 창을 확인해봅시다. 루트 디렉토리 화면을 배경으로 i/flow/login 페이지가 동시에 표시되고 있습니다. 저는 app router 를 학습하기 전까지는 createPortal 을 사용하여 포탈 영역에 로그인 컴포넌트를 띄우는 방식을 사용했었습니다. const NoLogin =()=...

Feb 1, 20244 min read

C/C++ 이진 트리(binary tree) 개요 및 구현(1)

개요 트리는 노드들이 나무 가지처럼 연결된 비선형 계층적 자료구조이다. 하위 트리가 존재하고, 그 노드에 또 하위 트리가 존재하는 자료구조 이다. 트리의 맨 위에 있는 루트 노드가 존재한다. 우리가 알아볼 트리는 이진 트리이다. 이진 트리는 자식 노드(부모로부터 아래로 이어진 노드)가 2개 이하인 구조를 말한다. 트리의 사용 사례로는 다음과 같다 계층 적 데이터 저장(파일,폴더) 효율적인 검색 속도 힙 데이터 베이스의 인덱싱 트리에 ...

Jan 31, 20244 min read

[React] Server component (RSC)

React.js 18 에 도입된 리액트 서버 컴포넌트는 서버에서 동작하는 리액트 컴포넌트를 의미합니다. Next가 권장하는 라우팅 방식인 app router의 기반이 되는 컴포넌트이기 때문에 app router 를 이해하기 위해서는 server component 에 대한 이해가 필요합니다. server component 리액트는 클라이언트단만을 컴포넌트화하는 대신, server component라는 개념을 통해 서버 영역을 컴포넌트화합니다. ...

Jan 29, 20243 min read

Flutter, JavaScript

42 posts