팀프로젝트를 진행하면서 적용하면 좋을 적절한 애니메이션을 고민하던 중,

아주 유용하게 사용할 수 있을 것 같은 라이브러리를 발견했다.

 

React-Spring의 가장 큰 장점은 애니메이션이 실행될때 re-render가 되지 않는다는 점이다.

일반적으로 react에서 useState 값을 사용하여 클릭 상태 변화에 따라 애니메이션을 다시 그려야하므로 리렌더 될 수 밖에 없다.

하지만 useSpring을 사용하면 해당 과정 없이 애니메이션을 동작시킬수 있다고 한다.

눈에 보이는 효과는 아직 없겠지만, 관리해야 할 useState가 많거나, 애니메이션을 많이 사용하게되면 매우 유용할 것 같다

 

import * as S from "./index.styled";
import { animated, useSpring } from "@react-spring/web";

export default function Page1() {
 
 const springs = useSpring({
    from: { x: 0 },
    to: { x: 100 },
  })


  return (
    <S.Container>
      <S.Wrapper>
        <animated.div
          style={{
            width: 80,
            height: 80,
            background: "#ff6d6d",
            borderRadius: 8,
            ...springs,
          }}
        />
      </S.Wrapper>
    </S.Container>
  );
}

일반적인 태그가 아니라 <animated.div/> 태그 의 style 속성으로 스타일할 수 있고, 애니메이션을 주기 위해서 useSpring을 사용해야한다. 이렇게 사용하면 첫 페이지 렌더링시 x가 100만큼 1번 이동한다. ( 배경 및 배치는 emotion/styled 사용 중 )

평소 사용하는 hooks 처럼 useSpring안에 원하는 애니메이션을 넣어주고 태그안에 ...spring을 바인딩시켜주면 끝이다!

 

클릭시 원하는 애니메이션을 작동시켜주는 것은 useSpring안에 api 라는 메서드를 추가하고, 함수로 변경하면된다.

  const [springs, api] = useSpring(() => ({
    from: { x: 0, y: 0 },
  }));

  const handleClick = () => {
    api.start({
      from: {
        x: 0,
        y: 0,
      },
      to: {
        x: 100,
        y: 100,
      },
    });
  };

handleClick은 animated.div 태그 onClick에 적용

그럼 React-Spring을 이용해서 아래 애니메이션을 만들어보자

CSS와 React만 사용해도 만들 수 있을 것 같지만 이번에는 React-Spring을 사용하면 좋을 것 같았다.

기본원리는 두 이미지가 동일한 위치와 사이즈로 있으며 투명도가 서로 0 -> 1, 1 -> 0 으로 변경되는고 x 축으로 180도씩 돌아가게 하는 것이다.

 

내가 사용하는 css 라이브러리인 emotion/styled와 예시 코드로 제공되는 css 방법이 다르기때문에 약간의 변화가 필요했다... 

useSpring 에서 제공하는 태그를 사용한 후 style을 적용해야 하므로 css에서 Wrapper 의 div, Wrapper의 span으로 구분하였다.

import * as S from "./index.styled";
import { animated, useSpring } from "@react-spring/web";
import { useState } from "react";

export default function Page1() {
  const [rotate, setRotate] = useState(false);
  const { transform, opacity } = useSpring({
    opacity: rotate ? 1 : 0,
    transform: `perspective(500px) rotateX(${rotate ? 180 : 0}deg)`,
  });

  const onClickRotate = () => {
    setRotate((prev) => !prev);
  };

  return (
    <S.Container>
      <S.Wrapper onClick={onClickRotate}>
        <animated.div
          style={{ opacity: opacity.to((o) => 1 - o), transform }}
        />
        <animated.span style={{ opacity, transform, rotateX: "180deg" }} />
      </S.Wrapper>
    </S.Container>
  );
}
import styled from "@emotion/styled";
import * as GS from "../../../../theme/global";

export const Container = styled.div`
  width: 100%;
  height: 100vh;
  background-color: ${GS.base.primary};
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
`;

export const Wrapper = styled.div`
  width: 82%;
  height: 80%;
  position: relative;

  div {
    display: flex;
    width: 500px;
    height: 300px;
    background-color: black;
    position: absolute;
    opacity: 1;
    cursor: pointer;

    ::before {
      content: "kk-jae 앞면입니다.";
      color: white;
    }
  }

  span {
    display: flex;
    width: 500px;
    height: 300px;
    background-color: pink;
    position: absolute;
    opacity: 0;
    cursor: pointer;

    ::before {
      content: "kk-jae 뒷면입니다";
    }
  }
`;

 

애니메이션을 다채롭게 적용하기 위해서는 css 셀렉터도 다시 한번 학습할 필요가 있을 것 같다.

 

 

React-Spring  https://www.react-spring.dev/

 

React Spring

Bring your components to life with simple spring animation primitives for React

www.react-spring.dev

+ Recent posts