React

[React] Framer Motion(5) Share Layout Animation를 사용한 애니메이션 효과 공유

cob 2022. 10. 3. 21:29
라이브러리 설치 및 기본 사용 법은 아래 링크에서 확인
https://cocococo.tistory.com/29

 

Share Layout Animation

레이아웃 공유 란?
서로 다른 애니메이션 효과를 자연스럽게 이어지도록 하는 방법이다.

 

 

 


1. Layout Animation ( CSS 변경을 통한 자동 애니메이션 적용 )

Layout에 prop을 사용한 애니메이션 적용 방법
Layout prop이란?
element에게 prop을 주어 CSS를 변경하게되면,   해당 element는 Layout이 바뀔 때 애니메이션 효과가 발생한다.
( CSS 때문에 Layout이 바뀐다면 저절로 애니메이션 효과가 이루어진다. )
function App() {
  const [clicked, setClicked] = useState(false);
  const toggleClicked = () => setClicked((prev) => !prev);
  return (
    <Wrapper onClick={toggleClicked}>
      <Box
        style={{
          justifyContent: clicked ? "center" : "flex-start",
          alignItems: clicked ? "center" : "flex-start",
        }}
      >
      	{/* 이동 되는 컴포넌트에 layout prop을 준다. */}
        <Circle layout />
      </Box>
    </Wrapper>
  );
}

export default App;
  • Layout Prop만 넣어주면 motion이 감지해 애니메이션 효과를 자동으로 넣어준다.

 

layout 옵션 차이 비교

 

 

 

 


2. Share Layout Animation ( 애니메이션 공유 )

서로 다은 애니메이션이 자연스럽게 이어지도록 공유하는 Layout 방법
* Source Code *
https://github.com/kangilbin/React.js/blob/master/animation/src/ShareLayoutAnimate.tsx
function App() {
  const [clicked, setClicked] = useState(false);
  const toggleClicked = () => setClicked((prev) => !prev);
  return (
    <Wrapper onClick={toggleClicked}>
      <Box>{!clicked ? <Circle layoutId="circle" /> : null}</Box>
      <Box>{clicked ? <Circle layoutId="circle" /> : null}</Box>
    </Wrapper>
  );
}

export default App;
  • layoutId : 동일한 loyoutId를 사용하게 되면, Framer(애니메이션 라이브러리)에게 같은 컴포넌트라고 알려주어 서로 다른 컴포넌트의 애니메이션이 자연스럽게 이어진다.

 

2-1) Share Layout Animation 사용 예

* Source Code *
https://github.com/kangilbin/React.js/blob/master/animation/src/ShareLayout2.tsx
import { AnimatePresence, motion } from "framer-motion";
import styled from "styled-components";
import { useState } from "react";

const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: space-around;
  align-items: center;
`;
const Grid = styled.div`
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  width: 50vw;
  gap: 10px;
  div:first-child,
  div:last-child {
    grid-column: span 2;
  }
`;

const Box = styled(motion.div)`
  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);
`;

const Overlay = styled(motion.div)`
  width: 100%;
  height: 100%;

  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const OverlayVariants = {
  initial: { backgroundColor: "rgba(0, 0, 0, 0)" },
  animate: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
  exit: { backgroundColor: "rgba(0, 0, 0, 0)" },
};

function App() {
  // null 또는 string type이라고 정의
  const [id, setId] = useState<null | string>(null);
  return (
    <Wrapper>
      <Grid>
        {["1", "2", "3", "4"].map((n) => (
          // layoutId는 string이어야 한다.
          <Box onClick={() => setId(n)} key={n} layoutId={n} />
        ))}
      </Grid>
      <AnimatePresence>
        {id && (
          <Overlay
            onClick={() => setId(null)}
            variants={OverlayVariants}
            initial="initial"
            animate="animate"
            exit="exit"
          >
           {/* 모달 layoutId */}
            <Box layoutId={id} style={{ width: 400, height: 200 }} />
          </Overlay>
        )}
      </AnimatePresence>
    </Wrapper>
  );
}

export default App;
  • 4개의 서로 다른 layoutId를 가진 컴포넌트를 만들고, 중앙의 모달 컴포넌트와 layoutId를 동일하게 바꿔어 주면서 자연스러운 애니메이션 효과를 만든다.
  • layoutId는 Type String만 가능하다.

Share Layout Animation

 

반응형