Netfilx Clone #3 Framer Motion(3)

Leesu·2022년 12월 20일
0

Framer Motion

✔️AnimatePresence

  • 공식문서는 여기
  • 컴포넌트가 React 트리에서 제거될 때 애니메이션 효과를 줄 수 있다.
  • React에는 다음과 같은 수명 주기 메서드가 없기 때문에 종료 애니메이션을 활성화한다.
  • 규칙
    • AnimatePresence 내부에 조건문이 있어야 사용이 가능하다
  • 사용 방법
import { motion, AnimatePresence } from "framer-motion"

export const MyComponent = ({ isVisible }) => (
  <AnimatePresence>
    {isVisible && (
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      />
    )}
  </AnimatePresence>
)
  • exit
    • 이 컴포넌트가 트리에서 제거될 때 애니메이션할 대상입니다.
  • 사용방법을 알았으니, 연습해보자!
  • click 버튼을 클릭하면 나타났다 사라지는 박스에 AnimatePresence 을 적용하여 애니메이션을 줄 것!
const boxVariants = {
  initial : { opacity: 0},
  visible: { opacity: 1 },
  leaving : { opacity: 0 }
}

function App() {
  const [ showing, setShowing ] = useState(false);
  const toggleShowing = () => setShowing(prev => !prev);
  return (
    <button onClick={toggleShowing}> Click! </button>
    <AnimatePresence>
      { showing ? (
        <Box 
          variants={boxVariants} 
          initial="initial"
          visible="visible"
          exit="leaving" // element 가 사라질때 동작할 애니메이션
          /> 
       ) : null}
    </AnimatePresence>
  );
};
  • initial
  • visible
  • exit (ㅋㅋ 서서히 opacity:0 이 되며 사라지는 중.. 캡처..)

✔️AnimatePresence 을 사용하여 BOX Slider 구현하기 ⭐⭐⭐

  • 넷플릭스 클론코딩의 중요 포인트 ~~! 박스 슬라이드 구현하기 연습 타임
  • 중요도가 있으니 ㅇㅇ 만큼 별 세개 주었다 그럼 렛츠고
function App() {
  return (
    <AnimatePresence>
      {[1, 2, 3, 4, 5, 6, 7, 8, 9 10].map( i => <Box key={i}>{i}</Box>}
    <AnimatePresence>
  )
}
  • 우선 10개의 박스를 만들어줬다
  • 이제, 한번에 한 box 씩 보여주자
function App() {
  const [visible, setVisivle] = useState(1);
  return (
    <AnimatePresence>
      {[1, 2, 3, 4, 5, 6, 7, 8, 9 10].map( i => 
        i === visible ? <Box key={i}>{i}</Box> : null
      }
    <AnimatePresence>
  )
}

  • 이제, i 를 1씩 증가시켜주는 기능을 만들자
const boxVar = {
  invisible : { x: 500, opacitiy: 0, scale: 0 },
  visible: { x: 0, opacitiy: 1, scale: 1  },
  exit : { x: -500, opacitiy: 0, scale: 0 }
}

function App() {
  const [visible, setVisivle] = useState(1);
  const nextPlease = () => setVisivle(prev => prev === 10 ? 10: prev +1 )
  return (
    <AnimatePresence>
      {[1, 2, 3, 4, 5, 6, 7, 8, 9 10].map( i => 
        i === visible ? <Box 
          variants={box}
          initial="invisible"
          animate="visible"
          exit="exit"
          key={i}
         > 
           {i} 
         </Box> : null
      }
    <AnimatePresence>
    <button onClick={nextPlease}> Next </button>
  )
}
  • prev 가 10과 같으면 10을 return 하고, 아니라면 prev 을 1씩 증가시키고,
    array 의 숫자가 visible state 와 같다면, 같은 것만 보여줌
  • next 버튼을 클릭하면 visible state 의 값이 1씩 증가하면서,
    오른쪽(x:500) 에서 박스가 오고, visible 상태이면 중앙에(x:0), 사라질땐 왼쪽(x:-500) 으로 사라진다.
  • visible state 가 1에서 2로 증가한다는 것은, 첫번째 박스인 1이 사라지고 2가 새로 생성된다는 뜻이다. 그러므로 AnimatePresence 에 의해 exit 애니메이션이 발생한다.

  • ㅋㅋ이렇게 된다
  • 다음으로 가는 버튼만 있으니 이전으로 돌아가는 기능(1씩 감소)도 만들어주자
const boxVar = {
  invisible : { x: 500, opacitiy: 0, scale: 0 },
  visible: { x: 0, opacitiy: 1, scale: 1  },
  exit : { x: -500, opacitiy: 0, scale: 0 }
}

function App() {
  const [visible, setVisivle] = useState(1);
  const nextPlease = () => setVisivle(prev => prev === 10 ? 10: prev +1 )
  const prevPlease = () => setVisivle(prev => prev === 1 ? 1: prev -1 )
  return (
    <AnimatePresence>
      {[1, 2, 3, 4, 5, 6, 7, 8, 9 10].map( i => 
        i === visible ? <Box 
          variants={box}
          initial="invisible"
          animate="visible"
          exit="exit"
          key={i}
         > 
           {i} 
         </Box> : null
      }
    <AnimatePresence>
    <button onClick={nextPlease}> Next </button>
    <button onClick={prevPlease}> Prev </button>
  )
}
  • 그런데 이렇게하면, 1씩 감소하긴 하는데.. 증가할때와 똑같이 오른쪽에서 왼쪽으로 나오는 애니메이션이 동일해서 햇갈린다.
  • 감소할때는 왼쪽에서 나와서 오른쪽으로 사라지게 하고,
    visible state 를 사용해 1~10개의 박스를 렌더링해오는 코드를 축소시켜보자.
const boxVar = {
  invisible : { x: 500, opacitiy: 0, scale: 0 },
  visible: { x: 0, opacitiy: 1, scale: 1  },
  exit : { x: -500, opacitiy: 0, scale: 0 }
}

function App() {
  const [visible, setVisivle] = useState(1);
  const nextPlease = () => setVisivle(prev => prev === 10 ? 10: prev +1 )
  const prevPlease = () => setVisivle(prev => prev === 1 ? 1: prev -1 )
  return (
    <AnimatePresence>
       <Box 
          variants={box}
          initial="invisible"
          animate="visible"
          exit="exit"
          key={visible} 
         > 
          {visible}  
        </Box> 
      }
    <AnimatePresence>
    <button onClick={nextPlease}> Next </button>
    <button onClick={prevPlease}> Prev </button>
  )
}
  • visible state 가 1부터 시작하여 1씩 증가하고 1씩 감소하니, key 에 부여하자.
    그럼 react js 는 key 값이 바뀔때마다 새로운 컴포넌트가 생겼다고 생각해, 컴포넌트를 리렌더해주고
    그 과정에서 컴포넌트가 삭제될때 AnimatePresence 를 통해 애니메이션이 실행된다.
  • 이제 방향을 바꿔줄 차례

✔️custom

  • 각 애니메이션 컴포넌트에 대해 동적 variants를 다르게 적용할 때 사용할 수 있는 사용자 지정 데이터.
  • 즉, variants 에 데이터를 보낼 수 있게 해주는 프로퍼티이다.
  • 사용 방법
const variants = {
  visible: (custom) => ({
    opacity: 1,
    transition: { delay: custom * 0.2 }
  })
}

< motion.div custom={0} animate="visible" variants={variants} />
< motion.div custom={1} animate="visible" variants={variants} />
< motion.div custom={2} animate="visible" variants={variants} />
  • 나의 경우 가고자 하는 방향에 따라서 invisible 과, exit 만 바꿔주면 되므로,
    custom 을 사용해 위치를 바꿔주자
const boxVar = {
  invisible : (isback:boolean) => ({  // back state & custom 의 값
  	 x: isback ? -500 : 500,   // 1이 감소한다면 왼쪽, 증가한다면 오른쪽에서 나타남
     opacitiy: 0, 
     scale: 0,
  })
  visible: { x: 0, opacitiy: 1, scale: 1  },
  exit : (isback:beelean) => ({  // back state & custom 의 값
     x: isback ? 500 : -500,  // 1이 감소한다면 오른쪽으로, 증가한다면 왼쪽으로 사라짐
    opacitiy: 0, 
    scale: 0
  })
}

function App() {
  const [visible, setVisivle] = useState(1);
  const [back, setBack] = useState(false);
  const nextPlease = () => {
    setBack(false);
    setVisivle(prev => prev === 10 ? 10: prev +1 );
  }
  const prevPlease = () => {
    setBack(true);
    setVisivle(prev => prev === 1 ? 1: prev -1 );
  }
  return (
    <AnimatePresence mode="wait" custom={back}>  <<<----
       <Box 
          custom={back}  <<<----
          variants={box}
          initial="invisible"
          animate="visible"
          exit="exit"
          key={visible} 
         > 
          {visible}  
        </Box> 
      }
    <AnimatePresence>
    <button onClick={nextPlease}> Next </button>
    <button onClick={prevPlease}> Prev </button>
  )
}
  • <AnimatePresence mode="wait">
    • true 로 설정하면 AnimatePresence 는 한 번에 하나의 컴포넌트만 랜더링한다.
      exiting중인 컴포넌트는 entering하는 컴포넌트가 렌더링되기 전에 exit 애니메이션을 완료합니다.
  • 이렇게 하면 !!!
    • next 버튼을 눌러 visible state 가 1씩 증가하면 back state 가 false 값을 가지므로 왼쪽에서 오른쪽으로 나타나고
    • prev 버튼을 눌러 visible state 가 1씩 감소하면 back state 가 true 값을 가지므로 오른쪽에서 왼쪽으로 사라진다.
profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글