Notice
Recent Posts
Recent Comments
Link
07-17 09:59
관리 메뉴

개발 블로그

Pokemon Card Flip - 7. Motion 라이브러리로 애니메이션 넣기 본문

토이프로젝트/Pokemon Card Flip

Pokemon Card Flip - 7. Motion 라이브러리로 애니메이션 넣기

hoj0806 2025. 3. 17. 20:06

https://motion.dev/

 

Motion - A modern animation library for JavaScript and React

Motion is built on native browser APIs for a tiny filesize and superfast performance. It uses hardware acceleration for smooth and eco-friendly animations. Previously Framer Motion.

motion.dev

 

Motion이란?

React에서 부드러운 애니메이션을 쉽게 구현할 수 있도록 도와주는 라이브러리

애니메이션을 직접 CSS로 만들 필요 없이, 간단한 props만으로 자연스러운 모션 효과를 적용이 가능
물리 기반(Spring) 애니메이션을 지원해서, 더 부드럽고 자연스러운 움직임을 만들 수 있음
자동 언마운트 애니메이션 (exit + AnimatePresence) 기능이 있어서, 요소가 사라질 때도 애니메이션을 추가할수 있음

 

 

import { motion } from "framer-motion";

const SelectButton: React.FC<{
  onMode: () => void;
  children: React.ReactNode;
  buttonColor: string;
}> = ({ onMode, children, buttonColor }) => {
  return (
    <motion.button
      onClick={onMode}
      initial={{ opacity: 0, y: 30 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: 30 }}
      transition={{ type: "spring" }}
      style={{ backgroundColor: buttonColor }}
      className={
        `bg-[${buttonColor}]` +
        "px-4 py-2 text-lg font-bold text-white border-4 border-black shadow-[4px_4px_0px_black] active:shadow-none active:translate-x-1 active:translate-y-1 w-[180px] md:w-[250px] lg:w-[400px] lg:h-[90px] lg:text-3xl"
      }
    >
      {children}
    </motion.button>
  );
};

export default SelectButton;

 

적용할 컴포넌트 이름앞에 motion.을 적어주면 적용이 가능하다

initial은 해당 컴포넌트가 최초 렌더링 될때 적용될 애니메이션이다 

animate는 렌더링 후 적용될 애니메이션이다

exit는 컴포넌트가 DOM에서 사라질때 적용될 애니메이션이다 exit를 사용하기 위해서는 부모 컴포넌트를 AnimationPresence로 감싸줘야 적용이 가능하다

 

import "./App.css";
import Main from "./components/Main";
import SelectDifference from "./components/SelectDifference";
import { useAppSelector } from "./hooks/useAppSelector";
import AppWrapper from "./layout/AppWrapper";
import { selectMode } from "./slice/modeSlice";
import { AnimatePresence } from "framer-motion";

const App = () => {
  const currentMode = useAppSelector(selectMode);

  return (
    <AppWrapper>
      <AnimatePresence mode='wait'>
        {currentMode === "main" && <Main />}
      </AnimatePresence>
      <AnimatePresence mode='wait'>
        {currentMode === "selectDifference" && <SelectDifference />}
      </AnimatePresence>
      <AnimatePresence>
        {currentMode === "game" && <div>게임화면입니다</div>}
      </AnimatePresence>
      {currentMode === "docs" && <div>도감화면입니다</div>}
    </AppWrapper>
  );
};

export default App;

 

현재 App.tsx에서 리덕스 툴킷으로 관리하고있는 currentMode값에따라 컴포넌트를 조건부로 렌더링한다 

import SelectButton from "../ui/SelectButton";
import { useAppDispatch } from "../hooks/useAppDispatch";
import { setMode } from "../slice/modeSlice";

const Main = () => {
  const dispatch = useAppDispatch();

  const selectDifferenceButtonHandler = () => {
    dispatch(setMode("selectDifference"));
  };

  const docsButtonHandler = () => {
    dispatch(setMode("docs"));
  };
  return (
    <div className='absolute bottom-[120px] left-1/2 -translate-x-1/2'>
      <div className='flex flex-col gap-5'>
        <SelectButton
          onMode={selectDifferenceButtonHandler}
          buttonColor='#181818'
        >
          게임시작
        </SelectButton>
        <SelectButton onMode={docsButtonHandler} buttonColor='#181818'>
          도감보기
        </SelectButton>
      </div>
    </div>
  );
};

export default Main;
import SelectButton from "../ui/SelectButton";
import { useAppDispatch } from "../hooks/useAppDispatch";
import { setMode } from "../slice/modeSlice";

const SelectDifference = () => {
  const dispatch = useAppDispatch();

  const gameButtonHandler = () => {
    dispatch(setMode("game"));
  };

  return (
    <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
      <div className='flex flex-col gap-[80px]'>
        <SelectButton buttonColor='#EF4444' onMode={gameButtonHandler}>
          쉬움
        </SelectButton>
        <SelectButton buttonColor='#FACC15' onMode={gameButtonHandler}>
          보통
        </SelectButton>
        <SelectButton buttonColor='#3B82F6' onMode={gameButtonHandler}>
          어려움
        </SelectButton>
      </div>
    </div>
  );
};

export default SelectDifference;

Motion으로 애니메이션이 적용된 모습