이번 섹션에서는 ReactJs용 라이브러리인Framer Motion
을 사용해서 애니메이션을 만드는 방법을 배워보자.
📎https://www.framer.com/motion/
npm install framer-motion
animate를 하기 원한다면 motion 패키지로부터 나와야한다. 일반 div
로는 사용할 수 없고, motion.div
로 사용할 수 있다.
저번 챕터에서 배웠듯이, 무언가를 애니메이트 할 때 motion으로부터 HTML element를 불러와야만 했다.
스타일 컴포넌트를 애니메이트 시킬 수 있는 방법은 다음과 같다.
const Box = styled(motion.div)``;
<Box transition={{ duration: 3 }} animate={{ borderRadius: "100px" }} />
애니메이션을 시작하는 방식을 명시하려면 initial
이라는 이름의 prop을 사용하면 된다.
variants
는 코드를 깔끔하게 해주고, 많은 애니메이션들을 하나로 연결시켜주는 역할을 한다.
const myVars = {
start: { scale: 0 },
end: { scale: 1, rotateZ: 360, transition: { type: "spring", delay: 0.5 } },
};
<Box variants={myVars} initial="start" animate="end" />
variants={myVars}를 써주고, initial에는 myVars 오브젝트 내의 property 이름을 적어주면 된다.
여기서 오브젝트와 프로퍼티 이름은 마음대로 써주면 된다!
부모인 Box에만 variants를 준 상황에서, 부모 컴포넌트가 variants와 initial, animate의 variant 이름을 갖고 있을 때 motion은 이것들을 복사해서 자동으로 자식들에게 붙여준다.
위, 아래 두개의 코드는 똑같이 동작한다.
<Box variants={boxVariants} initial="start" animate="end">
<Circle />
<Circle />
<Circle />
<Circle />
</Box>
<Box variants={boxVariants} initial="start" animate="end">
<Circle initial="start" animate="end"/>
<Circle initial="start" animate="end"/>
<Circle initial="start" animate="end"/>
<Circle initial="start" animate="end"/>
</Box>
위의 코드처럼 Motion은 자식들 각각에 복사 붙여넣기 해주기 때문에 circleVariants는 boxVariants의 이름들을 똑같이 써주면 된다.
부모의 initial 값과 animate 값을 상속한다고 생각하면 된다!
✨부모 variants 내에서 원한다면 delayChildren
을 사용하여 모든 자식들에게 delay를 줄 수 있다.
✨staggerChildren
을 사용하면 쉽게 구현할 수 있는데,첫번째 원에 0.5초 delay를 줄 것이고 1초, 1.5초, 2초 순으로 자동적으로 delay를 주게 된다.
<Box
whileHover={{ scale: 1.5, rotateZ: 90 }}
whileTap={{ scale: 1, borderRadius: "100px" }} />
whileHover, whileTap 안에 오브젝트를 넣는 것 대신에 두 Variants를 만들어 넣어어보자.
const boxVariants = {
hover: { scale: 1.5, rotateZ: 90 },
click: { scale: 1, borderRadius: "100px" },
};
<Box variants={boxVariants} whileHover="hover" whileTap="click" />
✅ drag
만 써주면, 바로 드래그 할 수 있다💫
✅ whileDrag에 backgroundColor를 넣으려고 하는데 예를들어 string인 "blue"를 넣어도 즉각적으로 동작하지만 애니메이트하기 어려우므로 rgba
또는 rgb
를 이용해서 값을 넣어주면 된다.
드래그 제약(contraints) 에 대해 알아보자.
drag="x"
라고 작성하면 x선 좌표 내에서만 드래그할 수 있다.
dragConstraints
는 기본적으로 제약이 있고 드래깅이 허용될 수 있는 영역인 Box를 만들 수 있다.
중앙 박스가 바깥쪽 박스에 의해 제약이 되게 만드는 법을 배워보자.
✅ 1. 직접 수 계산을 해서 영역 제한하기
<Box
drag
dragConstraints={{ top: -200, bottom: 200, left: -200, right: 200 }} />
✅ 2. ref
이용하기 👍
const biggerBoxRef = useRef<HTMLDivElement>(null);
<BiggerBox ref={biggerBoxRef}>
<Box drag dragConstraints={biggerBoxRef} />
✨Box가 중앙으로 되돌아가게 하려면 dragSnapToOrigin
을 쓰기만 하면 된다!
dragElastic
은 기본적으로 당기는 힘이 있고, 0에서 1사이의 수로 표현해주면 되는데 기본값은 0.5이다.
애니메이션 내의 수치를 트래킹할 때 필요한 MotionValue
를 배워보자.
function App() {
const x = useMotionValue(0);
console.log(x);
return (
<Wrapper>
<Box style={{ x: x }} drag="x" dragSnapToOrigin />
</Wrapper>
);
}
{x:x}를 shortcut으로 {x}로 작성해도 된다.
console.log 코드가 있지만 Box를 움직여도 콘솔에 한번만 출력이 된다. MotionValue가 업데이트 될 때 React Rendering Cycle(렌더링 싸이클)을 발생시키지 않기 때문이다. 즉, MotionValue가 ReactJs State 가 아니라는 것.
따라서 MotionValue가 바뀌어도 내 컴포넌트가 재렌더링되지 않는다.
useEffect(() => {
x.onChange(() => console.log(x.get()));
}, [x]);
MotionValue가 업데이트 되었다고 하는데, onChange를 쓰는 대신 useMotionValueEvent
를 사용해서 코드를 작성하면 된다.
useTransform
을 이용해서 x값을 transforming 해보자.
useScroll
은 MotionValue이다. 즉 state가 아니며 재렌더링을 발동시키지 않는 것을 의미한다.
(최신버전에서는 useViewportScroll ➡ useScroll로 이름 변경됨)
scrollY
는 픽셀 단위, scrollYProgress
는 0과 1사이의 값으로 스크롤 간격을 알려준다.