React - 컴포넌트 전환 애니메이션(transition) 만드는 4단계

thisishwarang·2023년 1월 2일
0

컴포넌트가 등장, 퇴장할때 애니메이션이 있으면 더 예뻐보일 것이다.
opacity가 변하거나 scale이 변하는 등등 간단한것들을 css를 활용하여 만들어보자!

애니메이션 만드는 개발step
1. 애니메이션 동작 전 스타일을 담을 className 만들기
2. 애니메이션 동작 후 스타일을 담을 className 만들기
3. transition 속성도 추가
4. 원할 때 2번 탈부착

저번에 만들었던 tab 버튼을 눌렀을때의 내용이 opacity에 의해 서서히 등장하는 애니메이션 만들어보자

1. 애니메이션 동작 전, 2. 후 스타일 담을 className 만들기

//App.css
.start {
  opacity: 0;
}
.end {
  opacity: 1;
}

App.css파일에 className 두개를 추가해서 opacity를 0->1로 만들어 보자

3. transition 추가

.start {
  opacity: 0;
}
.end {
  opacity: 1;
  transition: opacity 0.5s; 
  /* opacity가 변경될 때 0.5초에 걸쳐서 변경해주세요 라는 뜻 */
}

애니메이션 동작 후 스타일에 transition 속성으로 opacity가 변경될 때 0.5초에 걸쳐 변경하라고 코드를 작성함

function TabContent({tab}) {
    return (<div className='start end'>
        {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
    </div>)
}

이렇게 컴포넌트를 div태그로 묶어서 className에 아까 만든걸 추가 (이때 end는 떼었다 붙였다 해야 애니메이션이 바뀌는것을 알 수 있음)

4. 원할때 부착하기

tab버튼을 누를때마다 end를 부착하라는 코드를 짜야하는데 이를 각 버튼마다 만들면 3번이나 같은 코드를 적어야 한다. 그래서 컴포넌트에 useEffect()를 사용하여 tab state가 변할때마다 내부 코드를 실행시키는 방식으로 해결했다.

function TabContent({tab}) {

    let [fade, setFade] = useState('')
    useEffect(()=>{
        setFade('end')
    }, [tab])

    return (<div className={`start ${fade}`}>
        {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
    </div>)
}

tab 버튼을 누를때 end가 붙었다 땠다 하는 동적인 UI를 원하기 때문에 동적인 UI만드는 방법에 따라 fade라는 state를 만들어서 className에 추가하고 tab이란 state가 변하면 setFade('end')를 추가하도록 만들었다.

하지만 end가 한번 부착되고 다시 떼지는 코드가 없기 때문에 이 코드가 필요하다!
useEffect 내부 코드가 실행되기 전에 코드를 실행하는 기능을 가진 return을 사용해서 다음과 같이 코드를 작성했다

function TabContent({tab}) {

    let [fade, setFade] = useState('')
    useEffect(()=>{
        setFade('end')
        return (()=>{
            setFade('')
        })
    }, [tab])

    return (<div className={`start ${fade}`}>
        {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
    </div>)
}

=> 이제 tab이 변경되면 fade가 ''가 되었다가 'end'가 될것이다.

근데 또 안됨... 왜 안되는가??
react 18버전 이상부터 automatic batch라는 기능이 생겨서 state 변경함수들이 연달아 여러개 처리되어야 하면 다 처리하고 마지막 한번만 재렌더링을 해서 그렇다고 합니다.
그래서 시간차를 주기 위해 타이머를 설정

function TabContent({tab}) {

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

    return (<div className={`start ${fade}`}>
        {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
    </div>)
}

이제 잘됨

출처 : https://codingapple.com/

0개의 댓글