Framer-motion 라이브러리

박찬영·2023년 5월 27일
0

Framer-motion 라이브러리

framer-motion


Framer-motion

https://www.framer.com/docs/

공식문서 ☝☝☝

Framer Motion은 모션 그래픽과 애니메이션을 구현하기 위한 라이브러리로, React 기반의 웹 애플리케이션 개발에 사용됩니다. 사용자 인터페이스 요소에 다양한 애니메이션 효과를 적용할 수 있으며, 사용하기 쉽고 강력한 기능을 제공합니다

기본 사용법

$ npm i framer-motion

import { motion } from "framer-motion"

<motion.div
  initial={{ scale: 0 }} 
  animate={{ scale: 1, rotateZ: 360 }}
/>

initial 🔗ㅤ

처음 애니메이션 시작 상태를 정의합니다.

animate 🔗ㅤ

해당 요소가 최종적으로 어떻게 바뀔지 정의합니다.

transition 🔗ㅤ

애니메이션의 delay 혹은 duration 등을 정의할 수 있습니다.

<motion.div
  initial={{ opacity: 0, scale: 0.5 }}
  animate={{ opacity: 1, scale: 1 }}
  transition={{
    duration: 0.8,
    delay: 0.5,
    ease: [0, 0.71, 0.2, 1.01]
  }}
/>

Exit animations 🔗ㅤ

리액트에서는 컴포넌트가 트리에서 삭제될 경우 “즉시” 사라져버리기 때문에 사라지는 애니메이션을 적용하기 어렵다는 문제가 있습니다.

하지만 AnimatePresence 컴포넌트를 사용하면 사라지는 애니메이션이 보여지는 동안 DOM에 유지되도록 할 수 있습니다.

import "./styles.css";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";

export default function App() {
  const [value, setValue] = useState("false");
  return (
    <div className="App">
      <button onClick={() => setValue(true)}>보여주기</button>
      <button onClick={() => setValue(false)}>사라지기</button>
      <AnimatePresence>
        {value && (
          <motion.div
            className="box"
            initial={{ scale: 0 }}
            animate={{ scale: 1, rotateZ: 360 }}
            exit={{ scale: 0, rotateZ: 0 }}
            transition={{
              duration: 0.8,
              delay: 0.5,
              ease: [0, 0.71, 0.2, 1.01]
            }}
          />
        )}
      </AnimatePresence>
    </div>
  );
}

Keyframes 🔗ㅤ

animate의 값을 배열로 설정하면 Motion이 각 값을 차례로 처리합니다. 현재값을 초기 키프레임으로 사용하고 싶다면 null 값을 주면 됩니다.
이렇게 하면 애니메이션 되는 도중에 애니메이션이 시작되더라도 전환이 자연스러워집니다.

      <AnimatePresence>
        {value && (
          <motion.div
            className="box"
            animate={{
              scale: [1, 2, 2, 1, 1],
              rotate: [0, 0, 180, 180, 0],
              borderRadius: [
                "0%", "0%", "50%", "50%", "0%"
              ]
            }}
            transition={{
              duration: 2,
              ease: "easeInOut",
              times: [0, 0.2, 0.5, 0.8, 1],
              repeat: Infinity,
              repeatDelay: 1
            }}
          />
        )}
      </AnimatePresence>

여기서 times 를 배열로 설정하면 내가 원하는
시간을 마음대로 조정할 수 있습니다.
rpeat 은 몇번 반복할건지, repeatDelay 는 애니메이션이 끝난후 몇초 기다릴 건지 정의합니다.

Gesture animations 🔗ㅤ

hover, tap, drag, focus, inView 등의 제스처가 시작될 때 값 집합에 애니메이션을 적용할 수도 있습니다.

<motion.div
	initial={{ opacity: 0.2 }}
	whileInView={{
	  opacity: 1,
	  rotate: [0, 360],
	  borderRadius: ["20%", "50%"],
	  transition: { delay: 0.05 }
	}}
	whileHover={{
	  scale: 1.2,
	  transition: { type: "spring", stiffness: 400, damping: 10 }
	}}
/>

whileHover ={{}}
whileInView ={{}}
등등이 있습니다.

Variants 🔗ㅤ

DOM 전체에 파생되는 애니메이션을 사용하고 싶을때 쓰입니다.
즉 여러 motion.div 나 다른 motion.li.. 등등 과 같은 곳에서 공통적으로 쓰고 싶은 요소가 있을때 유용합니다.

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

<motion.div
  initial="hidden"
  animate="visible"
  variants={variants}
/>

Propagation 🔗ㅤ

만약 motion 컴포넌트에 자식 요소가 있다면, 자식 요소가 자체 animate 속성을 정의하기 전까지 variants의 변화를 상속받도록 할 수 있습니다.

쉽게 말해, variants에 정의한 속성명을 자식에게 그대로 물려줄 수 있습니다.

export default function App() {
  const list = {
    hidden: { opacity: 0 },
    visible: { opacity: 1 }
  };

  const item = {
    hidden: { opacity: 0, y: 100 },
    visible: { opacity: 1, y: 0 }
  };

  return (
    <div className="wrap">
      <motion.ul variants={list} initial="hidden" animate="visible">
        <motion.li variants={item}>item 1</motion.li>
        <motion.li variants={item}>item 2</motion.li>
        <motion.li variants={item}>item 3</motion.li>
      </motion.ul>
    </div>
  );
}

Orchestration 🔗ㅤ

위의 예제에서 볼 수 있는 것처럼, item에 달린 애니메이션은 모두 동시에 시작됩니다.
하지만 transition에 추가적인 속성을 더해 자식 애니메이션의 실행을 조정할 수 있습니다.

export default function App() {
  const list = {
    hidden: {
      opacity: 0
    },
    visible: {
      opacity: 1,
      transition: {
        when: "beforeChildren",
        staggerChildren: 0.2
      }
    }
  };

  const item = {
    hidden: { opacity: 0, y: 50 },
    visible: { opacity: 1, y: 0 }
  };

  return (
    <div className="wrap">
      <motion.ul variants={list} initial="hidden" animate="visible">
        <motion.li variants={item}>item 1</motion.li>
        <motion.li variants={item}>item 2</motion.li>
        <motion.li variants={item}>item 3</motion.li>
      </motion.ul>
    </div>
  );
}

Dynamic variants 🔗ㅤ

함수를 정의해서 각 variant에 동적으로 애니메이션을 설정할 수도 있습니다.
이러한 variant 함수들은 컴포넌트의 custom 속성으로 넘어오는 값을 인자로 받습니다.

export default function App() {
  const variants: {} = {
    hidden: {
      opacity: 0.2,
      y: 15
    },
    visible: (i: number) => ({
      opacity: 1,
      y: 0,
      transition: {
        delay: i * 0.2,
        duration: 1,
        repeat: Infinity,
        repeatType: "reverse"
      }
    })
  };

  const items = ["️❤️", "💛", "💜"];

  return (
    <div className="wrap">
      <ul>
        {items.map((item, i) => (
          <motion.li
            key={item}
            initial="hidden"
            animate="visible"
            variants={variants}
            custom={i}
          >
            {item}
          </motion.li>
        ))}
      </ul>
    </div>
  );
}

Manual Controls 🔗ㅤ

대부분의 UI 인터랙션에 맞춰 착착 애니메이션이 실행되지만,
좀더 복잡한 시퀀스를 구현하고 싶다면 useAnimationControls 훅으로 애니메이션을 수동 시작/중지할 수 있습니다.

import { useEffect, useState } from "react";
import { motion, useAnimationControls } from "framer-motion";
 
export default function App() {
  const [show, setShow] = useState(false);
  const controls = useAnimationControls();
 
  useEffect(() => {
    if (show) {
      controls.start({ scale: 6 });
    }
  }, [controls, show]);
 
  return (
    <div className="wrap">
      <motion.h1 animate={controls}>{show ? "Wow!" : "..."}</motion.h1>
      <button onClick={() => setShow(true)}>setShow(true)</button>
    </div>
  );
}
profile
오류는 도전, 코드는 예술

0개의 댓글