[CSS/React] mount/unmount 시 애니메이션 주기

dosilv·2021년 5월 16일
41
post-thumbnail

첫 번째 프로젝트로 이솝 홈페이지를 클론코딩 중인데, 맡은 컴포넌트 중에서 젤 애먹었던 modal menu.... 열고 닫는 건 조건부 렌더링으로 하면 되는 거 알겠는데! 나타날 때랑 사라질 때(특!히! 사라질 때! 😫) 애니메이션 구현하는 방법을 몰라서 🐕고생했다. 💢💢💢

이것저것 막 시도하다 어떻게 성공은 했는데, 까먹을 것 같아서 & 혹시 나 같은 고민에 빠질 사람들을 위해서 해두는 정리! (되긴 되지만.. 맞는 방법인진 모름>.<;;)



🎂 [CSS] keyframes 만들기

먼저 CSS에서 @keyframes로 원하는 효과를 만든다!

@keyframes 애니메이션 이름 {
  from {원하는 시작 속성}
  to {원하는 마지막 속성}
}

더 복잡한 효과를 원한다면... 원하는 만큼 %마다 끊어서 줄 수도 있음!

@keyframes 애니메이션 이름 {
  0% {원하는 속성}
  25% {원하는 속성}
  50% {원하는 속성}
  100% {원하는 속성}
}

나는 제품 리스트가 살짝 위에서 아래로 내려오며+투명했다가 나타나게 렌더링되도록 smoothAppear이라는 애니메이션과,

@keyframes smoothAppear {
  from {
    opacity: 0;
    transform: translateY(-5%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

메뉴가 스르륵 열리고 닫히도록 하기 위해서 slider라는 애니메이션을 만들었다.

@keyframes slide {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0%);
  }
}


🧁 [CSS] class selector + animation property

그 다음! 애니메이션을 동적으로 주기 위해 class 명을 하나 만든다. 만약 mount될 때만 애니메이션을 적용시킬 거면 이 단계는 생략해도 됨!

아래처럼 클래스이름을 선택자로 해서 위에서 만든 keyfames로 animation 속성을 넣어 준다.

.클래스명 {
  animation: [애니메이션 이름] [지속시간] 
}

지속시간 뒤에 다른 조건을 더 추가할 수도 있다. 자세한 건.... 요기서 CSS animation 참고~~

smoothAppear은 처음 등장할 때만 줄 애니메이션이라서 생략하고, 메뉴 열고 닫기는 아래처럼 만들었다. reverse는 slide keyframes를 반대로 (to 속성부터 from 속성으로) 적용한다는 의미고, &는 네스팅 때문에 써줌!

&.openAnimation {
  animation: slide 1s ease-in-out 0s 1 normal forwards;
}

&.closeAnimation {
  animation: slide 0.5s ease-in-out 0s 1 reverse forwards;
}


🍭 [React] mount OR unmount 시 애니메이션 주기

mount될 때만! 애니메이션 주는 건 완전 간단. 그냥 해당 요소의 CSS에 animation 속성만 추가해 주면 됨~~ 그럼 처음 마운트될 때 자동으로 적용된다.

.productCard {
  min-width: 340px;
  height: 530px;
  .
  .
  .
  animation: smoothAppear 1s;  <-추가
}

결과물 🌸


반대로 unmount될 때 적용하고 싶으면 위에서 따로 만든 클래스명을 React로 unmount 직전에 넣어 주면 된다. 그러니까

  1. state 변수를 하나 만들어서 빈 스트링으로 두고,
  2. 애니메이션을 적용할 요소의 className에 해당 state값을 넣어 둔다. (기존 클래스명이 있다면 백틱 등을 이용!)
  3. unmount를 실행하기 전에 setState로 빈 스트링을 애니메이션 속성을 담고 있는 클래스명으로 바꿔준다.

여기서 중요한 건❗ unmount 되기 전에❗ 해야 한다. 아니면 애니메이션이 실행될 시간도 없이 바로 컴포넌트가 사라지기 때문.......😓 그래서 setTimeout 같을 써서 unmount 작업을 animation 실행 시간만큼 늦춰 줬다.

  • 애니메이션을 적용할 컴포넌트
<div className={`menuColumn ${animation}`}>
...
</div>
  • 컴포넌트를 unmount하기 위한 함수
close = () => {
  this.setState({
    animation: 'closeAnimation',
  });
  setTimeout(this.props.menuToggle, 500);    //menuToggle이 modal과 관련된 상태값을 false로 만들어 컴포넌트를 끄는 함수임! 
};


🍧 [React] mount AND unmount 둘 다! 애니메이션 주기

mount될 때와 unmount될 때 둘 다 애니메이션을 주기 위해서는 하나의 과정이 더 필요하다. 단순하게 생각하면 위에서 한 거 둘 다 하면 안 되나?! 싶지만... 안댐..... 그럼 뒤에 추가된 unmount용 애니메이션이 작동을 안 한다! 대체 뭐가 잘못된 건지 몰라서 한참 헤맴 😭

각각 하나씩 할 땐 분명 되는데! 왜 말을 안 듣는지 개발자도구를 켜서 이것저것 확인해 본 결과.... animation 속성이 없는 요소에 animation 속성을 추가하면 추가되는 그 시점에서 효과가 실행되지만, 이미 animation 속성을 가진 요소에 새로 animation을 추가하면 속성이 덮어씌워지기는 하지만 그때 새 애니메이션이 실행되지는 않는 것 같다.

그래서 여러 가지 시도 끝에 찾아낸 방법... mount될 때 animation을 줬다가 ➡ 효과가 끝난 후 animation 속성을 아예 없앴다가 ➡ 다시 unmount 전에 추가하면 된다! 그래서 동적으로 스타일을 바꿔줘야 해서 클래스명이 두 개 필요한 것...!

  1. 클래스명을 바꾸기 위해 state 변수를 설정하되, 초기값으로 빈 스트링 대신 mount시 animation 속성을 담은 클래스명! 을 준다.
this.state = { animation: 'openAnimation' }

그리고 효과를 적용할 요소의 className에 변수를 넣어 놓는다.

<div className={`menuColumn ${animation}`}>
...
</div>

  1. 마운트 이후 효과가 실행되고 나면 animation 속성을 지워 주기 위해서, componentDidMount 영역에서 state변수를 빈 스트링으로 초기화한다! 대신 이때도 setTimeout으로 this.setState를 애니메이션 실행 시간만큼 지연시켜줘야 함~~~
componentDidMount() {
  setTimeout(() => {
    this.setState({ animation: '' });
  }, 1000);
}  

  1. 그리고 위에서 했던 거랑 똑같이 setTimeout을 이용해 unmount되기 전에 state 변수를 unmount 애니메이션을 담은 클래스명으로 바꿔 준다.
close = () => {
  this.setState({
    animation: 'closeAnimation',
  });
  setTimeout(this.props.menuToggle, 500);
};

결과물2 🌸🌸🌸

이런 방법으로 스르륵 등장하고 스르륵 사라지는 컴포넌트를 만들 수 있었다. 분명 더 좋은 방법이나.. 간편한 라이브러리가 있을 것 같지만..... 1차 프로젝트 때 라이브러리 사용은 지양한다고 했기 때문에! 앞으로 차근차근 배워나갈 것...⭐



출처는 길고 긴 내 시행착오~~~ 🤦‍♀️🤦‍♀️

profile
DevelOpErUN 성장일기🌈

1개의 댓글

comment-user-thumbnail
2023년 1월 25일

ㅆㅅㅌㅊ!

답글 달기