[React] - 컴포넌트 전환 애니메이션

오유민·2024년 1월 26일

오늘은 지난 시간에 만들었던 상세 페이지의 탭 UI가 서서히 등장하는 fade in 효과를 생성해보자. 간단히 정리하면 컴포넌트를 load할 때 투명도를 0에서 1로 바꾸어주면 되는데 css에서만 하면 적용되지 않으므로 useEffect()를 적용해보자.

애니메이션 적용하는 법

  1. 애니메이션이 동작되기 전 상태를 담을 className 생성
  2. 애니메이션이 동작된 후 상태를 담을 className 생성
  3. transition(전환) 속성 추가
  4. 원하는 곳에 2 붙이기

1~3 단계

/* App.css */
.animationStart {
	opacity: 0;
}

.animationEnd {
	opacity: 1;
    transition: opacity 0.5s;
}

transition은 해당 속성이 서서히 변하도록 해준다. 이제 원하는 <div> 요소에 animationStart를 넣어준 뒤 animationEnd를 탈부착할 때마다 fade in이 된다.

function Tab({tab}){

  return (
    <div className="animationStart animationEnd">
      { [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab] }
    </div>
  )
}

animationEnd라는 className을 떼었다가 붙여보면 실제로 애니메이션이 동작하는 걸 확인할 수 있다.

그럼 이제 구체적으로 내가 원할 때마다 animation이 작동되는 코드를 생성해보자. 만약 '버튼을 누를 때마다 animationEnd를 부착해주세요'라는 코드를 생성한다 생각했을 때, 버튼이 3개라면 end 부착 코드도 3개가 필요하게 된다. 모든 버튼 태그에 className을 추가해주어야 하기 때문이다.

코드를 더 깔끔하게 리액트적인 방법으로 짜보려면 useEffect()를 사용하면 된다. useEffect를 사용하면 특정 state나 props가 변경될 때마다 코드 실행이 가능했다. 그러므로 tab이라는 state가 변할 때 animationEnd를 해당 태그에 부착하는 코드를 짜면 애니메이션 구현 성공이다.

tab이 변할 때 end를 부착하기 위해서는 동적인 UI를 만들어야 한다.

  • 애니메이션 효과 적용을 위한 fade라는 state 생성
  • state에 따라 className이 어떻게 보일지 작성
  • 원할 때 fade 변경하기 (state 변경 함수 사용)
function Tab({tab}) {
  let [fade, setFade] = useState('')
  
  useEffect(()=>{
  	setFade('animationEnd')
  }, [tab])
  
  return (
  	<div className = {'animationStart ' + fade} >
    	{ [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab] }
    </div>
  )
}

이제 tab이라는 state가 변할 때마다 fade라는 state가 'animationEnd'로 변하고, className은 'animationStart animationEnd'로 변하게 된다. 하지만 이렇게만 해서는 애니메이션이 실제로 동작하지 않는다. animationEnd라는 클래스명을 부착하는 것은 맞지만 이를 className에 붙였다가 떼는 동작이 추가적으로 필요하다.

function Tab({tab}) {
  let [fade, setFade] = useState('')
  
  useEffect(()=>{
  	setTimeout( () => { setFade('animationEnd') }, 100)
    return ()=>{
  		setFade('')
  	}
  }, [tab])

  
  return (
  	<div className = {'animationStart ' + fade} >
    	{ [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab] }
    </div>
  )
}

useEffect 안에서 setTimeout으로 시간을 두어 animationEnd를 탈부착하도록 했다. 또 return문으로 clean up function 안에 fade라는 state를 공백으로 바꾸라고 해두었기 때문에 useEffect가 실행되기 전에는 'animationEnd'가 ''(공백)으로 바뀐다.

profile
개발자연습생의 개발 일기

0개의 댓글