so woon!

[FRAMER MOTION] useMotionValue + useTransform 사용하기 본문

Framer Motion/개념정리

[FRAMER MOTION] useMotionValue + useTransform 사용하기

xowoony 2023. 5. 13. 16:26

학습일 : 2023. 05. 13



useMotionValue

애니메이션 내의 수치를 트래킹(추적)하고자 할 때 사용할 수 있다.

예를 들면
아래 코드에서는 motion.div의 x좌표를 추적하고 있다.


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

export function MyComponent() {
  const x = useMotionValue(0)
  return <motion.div style={{ x }} />
}



유저가 왼쪽으로 드래깅하는지, 오른쪽으로 드래깅하는지의 여부를 알고 싶을 때
사용할 수 있을 것이다.



값을 추적하기 위해서는 useMotionValue를 import 해주어야 하고
style={{  x  }}를 써줘서 useMotionValue와 style의 x를 연결해주도록 한다.

 


<App.tsx>
style의 x좌표가 바뀔 때마다 MotionValue 역시 업데이트 됨

function App() {
  const x = useMotionValue(0);
  return (
    <Wrapper>
      <Box style={{ x }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;




참고로 MotionValue가 바뀌어도 컴포넌트는 다시 렌더링 되지 않는다.



변하는 x의 값을 확인해보기 위해
useEffect를 사용하여 확인해보도록 한다.

 

 


<App.tsx>

import { styled } from "styled-components";
import { motion, useMotionValue } from "framer-motion";
import { useEffect } from "react";

// style
const Wrapper = styled.div`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// 박스
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 40px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;

function App() {
  const x = useMotionValue(0);
  
// useEffect 사용으로 x값 추적하기
// x값이 바뀔때마다 x값이 콘솔에 찍혀나옴.
  useEffect(() => {
    x.on("change", () => console.log(x.get()));
  }, [x]);


  return (
    <Wrapper>
      <Box style={{ x }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;



실행결과




이번엔 버튼을 하나 만들어서 
그 버튼을 클릭했을 때 x 위치를 바꿀수도 있음

<App.tsx>

button에 onClick={()=> x.set(200)} 을 적어줌

import { styled } from "styled-components";
import { motion, useMotionValue } from "framer-motion";
import { useEffect } from "react";

// style
const Wrapper = styled.div`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// 박스
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 40px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;

function App() {
  const x = useMotionValue(0);
  
  return (
    <Wrapper>
      <button onClick={() => x.set(200)}>click me</button>
      <Box style={{ x }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;





실행결과



useTransform 사용하기

 


1. 박스를 드래그하는 위치에 따라 크기 변경하기


이번에는 사각형을 드래그해서 왼쪽 끝을 향하여 갈때
사각형을 점점 커지게
오른쪽 끝을 향해 갈때는 작아지게 해보고자 한다.


-800일 때 : scale이 2가 되도록 하고,
0일 때 : scale이 1이 되도록 하고,
800일 때 : scale이 0이 되도록
만들어 주면 되는데


 


useTransform에는 값을 3개 적어주어야 한다.

1.  값 : x
2.  검토하길 원하는 입력값 (x가 ___일 때 라는 의미) : 배열 [-800, 0, 800]
3.  얻길 원하는 출력값 : 배열을 적어줌 [2, 1, 0.1]

* 입력값의 갯수는 출력값의 갯수와 같아야함. *


 



function App() {
  const x = useMotionValue(0); // x값은 드래그할 때마다 새로 값이 설정됨

  const scaleValue = useTransform(x, [-800, 0, 800], [2, 1, 0.1]);
  // useEffect 대신 useMotionValueEvent 사용
  useMotionValueEvent(scaleValue, "change", (el) => console.log(el));
  return (
    <Wrapper>
      <button onClick={() => x.set(200)}>click me</button>
      <Box style={{ x }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;




실행결과
그리고 콘솔에 출력되어지는 값을 보면 -800이 되었을 때 2라는 값이 나오고
중간일 때에는 1, 
800이 되었을 때에는 0.1에 가까운 숫자가 찍혀나오는 걸 볼 수 있다.

 



React Native에서는
const scale = useTransform(x, [-800, 0, 800], [2, 1, 0.1]);
이 코드를 interpolation이라고 부른다.

useMotionValueEvent는 이제 필요 없으니 지워주도록 하고
이제 이것을 state와 연결시켜주면 된다.

 

 

import { styled } from "styled-components";
import { motion, useMotionValue, useMotionValueEvent, useTransform } from "framer-motion";

// style
const Wrapper = styled.div`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// 박스
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 40px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;


function App() {
  const x = useMotionValue(0);
  const scaleValue = useTransform(x, [-800, 0, 800], [2, 1, 0.1]);
  return (
    <Wrapper>
      <Box style={{ x, scale:scaleValue }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;




실행결과

 

 

 

 

 



2. 드래그 하는 위치에 따라 박스 회전하기

박스를 회전을 시켜보고자 하면 Box 컴포넌트 안 style에 rotate를 작성해주면 된다.
그리고 useTransform에 회전을 어떻게 시켜줄지 아래와 같이 적어주면 된다

import { styled } from "styled-components";
import { motion, useMotionValue, useTransform } from "framer-motion";

// style
const Wrapper = styled.div`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// 박스
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 40px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;


function App() {
  const x = useMotionValue(0);
  const rotateValue = useTransform(x, [-800, 800], [-360, 360]);
  return (
    <Wrapper>
      <Box style={{ x, rotateZ:rotateValue }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;




실행결과





3. 박스를 드래그 하는 위치에 따라 배경색 바꿔보기

역시 같은 방식으로 작성해주고 
배경이 될 Wrapper 컴포넌트에 style로 적용해주면 된다.

import { styled } from "styled-components";
import { motion, useMotionValue, useTransform } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// 박스
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 1);
  border-radius: 40px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;

function App() {
  const x = useMotionValue(0);
  const rotateZ = useTransform(x, [-800, 800], [-360, 360]);
  const gradient = useTransform(
    x,
    [-800, 800],
    [
      "linear-gradient(135deg, rgb(0, 210, 238), rgb(22, 103, 135))",
      "linear-gradient(135deg, rgb(52, 178, 145), rgb(212, 212, 107))",
    ]
  );
  return (
    <Wrapper style={{ background: gradient }}>
      <Box style={{ x, rotateZ: rotateZ }} drag="x" dragSnapToOrigin></Box>
    </Wrapper>
  );
}
export default App;




실행결과

 

 

 

 

'Framer Motion > 개념정리' 카테고리의 다른 글

[FRAMER MOTION] svg Animation  (0) 2023.05.14
[FRAMER MOTION] useScroll  (0) 2023.05.14
[FRAMER MOTION] Drag Constraint (드래그 제약)  (0) 2023.05.12
[FRAMER MOTION] Dragging  (0) 2023.05.11
[FRAMER MOTION] Gestures  (0) 2023.05.11
Comments