React에서 사용할 수 있는 production-ready 모션 라이브러리 입니다.
공식 홈페이지
공식 GitHub
npm i framer-motion
react 버전4를 사용하는 분들은 CRACO를 이용해 에러를 해결하세요.
CRACO(Create React App Configuration Override)는 create-react-app을 위한 configuration레이어 입니다.
animation
을 사용하기 위해서는 일반 HTML 테그를 사용할 수 없고, 꺽쇠안에 motion
을 아래와 같이 넣어줘야합니다.
<moiton.div></motion.div>
혹은 styled-components와 같이 사용을 하기 위해서는 아래와 같이 작성해줘야 합니다.
import {motion} from "framer-motion";
import styled from "styled-components";
const Box = styled(motion.div)``;
funtion App() {
return(
<Box />
);
}
export default App;
Framer Motion의 애니메이션은 모션 컴포넌트의 유연한 animate 속성을 통해 제어됩니다.
간단한 애니메이션의 경우 animate props에서 직접 설정할 수 있습니다.
<Box animate={{ rotate: 360 }} transition={{ duration: 2 }}/>
Transition은 값이 한 상태에서 다른 상태로 움직이는 방식을 정의합니다.
type을 통해서 Tween, spring과 같은 애니메이션의 유형을 설정할 수 있습니다.
기본 type 값은 spring 입니다.
<Box animate={{ rotate: 360 }} transition={{ type: "Tween" }}/>
Variants는 컴포넌트가 가질 수 있는 미리 정의 된 시각적 state입니다.
const BoxVariants = {
start: { opacity: 0.1 },
end: { opacity: 1,
transition: {
duration: 1.5,
delay: 1,
},
},
}
<Box variants={BoxVariants} initial="start" animate="end"/>
delayChildren: 딜레이 시간(초) 후에 하위 애니메이션이 시작됩니다.
staggerChildren: 하위 컴포넌트의 애니메이션에 지속 시간만큼 시차를 둘 수 있습니다.
const BiggerVariants = {
start: { opacity: 0.1 },
end: { opacity: 1,
transition: {
delay: 1,
duration: 1.5,
delayChildren: 1.5,
staggerChildren:0.1
},
},
}
const BoxVariants = {
start: {
opacity: 0,
y: -10,
},
end: {
opacity: 1,
y: 0,
}
}
<BiggerBox variants={BiggerVariants} initial="start" animate="end">
<Box variants={BoxVariants}/>
<Box variants={BoxVariants}/>
<Box variants={BoxVariants}/>
<Box variants={BoxVariants}/>
</BiggerBox>
🚨 부모 컴포넌트의 state값은 자식에게도 그대로 전달이 되는데, 자식에게도 새로운 state를 설정해 다른 애니메이션을 줄 수도 있습니다.
Hover 제스처는 포인터가 컴포넌트 위로 이동하거나 컴포넌트를 떠날 때를 감지합니다.
const BoxVariants = {
hover: { scale: 0.5 },
}
<Box variants={BoxVariants} whileHover="hover" />
컴포넌트를 클릭하고 있는 동안 애니메이션할 속성 또는 변형 레이블입니다.
const BoxVariants = {
click: { scale: 0.5 },
}
<Box variants={BoxVariants} whileTap="click" />
제약 없이 드래그를 하려면 컴포넌트에 Drag만 넣어주면 됩니다.
만약 특정 방향으로만 드래그하려면 "x" 또는 "y"로 설정합니다.
const BoxVariants = {
drag: {
// backgroundColor: "tomato",
backgroundColor: "rgb(255, 106, 86)",
transition: {
duration: 1.5,
}
},
}
<Box drag="x" variants={BoxVariants} whileDrag="drag" />
🚨 만약 backgroundColor 값에 blue나 tomato같은 값을 넣는다면 string이기 때문에 애니메이션이 나타나지 않습니다.
하지만 코드 = rgb값을 넣는다면 애니메이션이 실행됩니다. 그리고 transition값도 설정 할 수 있습니다.
true인 경우 드래그 가능한 요소는 드래그를 놓을 때, 원점으로 다시 애니메이션됩니다.
<Box drag dragSnapToOrigin />
아이템을 드래그 시 원점에서 움직임을 허용하는 정도입니다.
0 = 움직임 없음, 1 = 전체 움직임, 기본 값은 0.5입니다.
<Box drag dragElastic={0.2} />
드래그가 가능하도록 허용될 수 있는 영역을 설정할 수 있습니다.
dragConstraints에는 드래그 가능한 컴포넌트의 가장자리 거리를 정의합니다.
(드래그 가능한 영역에 가장자리에서 얼마만큼까지 허용할 것인지 지정)
props로 직접 설정도 가능합니다.
< BiggerBox>
< Box drag dragConstraints={{
top: 0, bottom: 50, left: 0, right: 50
}} />
< /BiggerBox>
const BoxRef = useRef(null);
< BiggerBox ref={BoxRef}>
< Box drag dragConstraints={BoxRef} />
< /BiggerBox>
MotionValues를 애니메이션 값의 상태와 속도를 추적합니다.
모든 모션 컴포넌트는 내부적으로 MotionValues를 사용하여 애니메이션 값의 상태와 속도를 추적합니다.
🚨 MotionValues는 react의 state값이 아니기 때문에 MotionValues의 값이 변하더라도 리랜더링이 되지 않습니다.
하지만 get 메소드로 확인할 수 있습니다.
onst x = useMotionValue(0);
useEffect(() => {
x.onChange(() => console.log(x.get()));
}, [x]);
<Box
style={{ x }}
drag="x"
dragSnapToOrigin
/>
set 메소드로 x의 값을 업데이트할 수 있습니다.
이 때, react에서 리랜더링을 트리거 하지 않습니다.
get 메소드로는 값을 읽을 수 있습니다.
MotionValue는 뭄자열이나 숫자가 될 수 있습니다.
useTransform 훅을 통해 MotionValues를 연결합니다.
useTRansform() 안에는 세가지 요소가 들어가는데, 첫 번째 요소로는 아이템이 변경 할 때마다 새로 설정되는 값을 넣어야합니다. 위에 설명한 것과 같이 MotionValue를 통해 값을 가져오면 됩니다.
두 번째로는 원하는 값을 배열에 넣습니다. 세 번째 인자로는 output을 넣습니다.
const scale = useTransform(x, [-400, 0, 400], [2, 1, 2]);
위 코드는 x축의 값이 -400일때 scale 값이 2, 중간이면 scale 값이 1, 400일때 scale 값이 2라는 뜻입니다.
위 상수를 컴포넌트의 style에 넣으면 됩니다.
뷰포트가 스크롤될 때 업데이트되는 MotionValues를 리턴합니다.
아래 값들은 모두 MotionValue< number >를 넘겨줍니다.
scrollX: 실제 수평 스크롤 픽셀 ex) 500px
scrollY: 실제 수직 스크롤 픽셀 ex) 500px
scrollXProgress : 0 ~ 1 사이의 수평 스크롤
scrollYProgress : 0 ~ 1 사이의 수직 스크롤(가장 상단 0, 가장 하단 1)
const { scrollYProgress } = useViewportScroll();
const scale = useTransform(scrollYProgress, [0, 1], [0.2, 1]);
<motion.div style={{ x }} />
AnimatePresence를 사용하면 React 트리에서 컴포넌트가 제거될 때 제거되는 컴포넌트에 애니메이션 효과를 줄 수 있습니다. 이 때, React에는 다음과 같은 생명주기 메서드가 없기 때문에 exit props를 사용해 활성화하고, 애니메이션 효과를 줄 수 있습니다.
const BoxVars = {
initial: {
scale: 0,
opacity: 0,
},
visible: {
scale: 1,
opacity: 1,
rotate: 180,
},
invisible: {
opacity: 0,
y: -20,
},
}
const [isShowing, setShowing] = useState(false);
const onClick = () => setShowing(prev => !prev);
<Wrapper>
<AnimatePresence>
{isShowing ?
<Box
variants={BoxVars}
initial="initial"
animate="visible"
exit="invisible"
/>
: null
}
</AnimatePresence>
<Button onClick={onClick}>click</Button>
</Wrapper>
각 애니메이션 컴포넌트에 대해 동적 variants를 다르게 적용할 때 사용할 수 있는 사용자 지정 데이터 입니다.
공식 문서 확인하기
true로 설정하면 AnimatePresence는 한 번에 하나의 컴포넌트만 랜더링합니다.
exiting 중인 컴포넌트가 완료될 때까지 기다렸다가 다음 컴포넌트가 애니메이션을 시작합니다.
공식 문서 확인하기
true인 경우 이 컴포넌트는 레이아웃이 변경될 댇 새 위치에 자동으로 애니메이션을 적용합니다.
크기나 위치가 변결 될 때 모션 컴포넌트의 레이아웃에 자동으로 애니메이션을 적용하려면 layout porp을 설정해줍니다.
function Layout() {
const [toggle, setToggle] = useState(false);
const clicked = () => setToggle(prev => !prev);
return (
<Wrapper onClick={clicked}>
<Box>
{toggle ? <Circle layoutId="move" /> : null}
</Box>
<Box>
{toggle ? null : <Circle layoutId="move" />}
</Box>
</Wrapper>
);
}
모션 컴포넌트의 layout prop은 레이아웃이 변할 때마다, 자동으로 애니메이션을 적용합니다.
동일한 layoutId prop을 가진 모션 컴포넌트들 간에 애니메이션을 적용할 수 있습니다.
layoutId가 있는 새 컴포넌트가 추가되고 다른 컴포넌가 제거되면 이전 컴포넌트에서 새 컴포넌트로 레이아웃 애니메이션을 수행합니다.