className
만들기 transition
속성 추가처음엔 안보이다가 end를 부착할 때 마다 fade-in이 되는 css
.start {
opacity : 0
}
.end {
opacity : 1;
transition : opacity .5s;
}
앞에 만든 탭메뉴 컨텐츠를 fade-in 시켜보기
원할 때 (tab button을 누를 때) end className 부착
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>][탭] }
</div>
)
}
useEffect 방식의 이론이라면 [tab]디펜던시로 인해 내용이 변하면 end라는 클래스가 적용되어야 한다.
하지만 위 방식은 되지 않는다.
리액트 18버전 이상부터는 automatic batch 라는 기능이 생겼다.
state 변경함수들이 연달아서 여러개 처리되어야한다면
state 변경함수를 다 처리하고 마지막에 한 번만 재렌더링된다.
그래서 'end' 로 state를 변경하는 것과 ' ' 빈값으로 변경하는 효과에 약간 시간차를 두어야한다.
setTimeout 말고 automatic batching을 막아주는 flushSync()를 찾아봐도 좋을 것 같다.
최종 작동코드 (clean-up-function 추가)
function TabContent({tab}){
// 초기 빈값 (div ClassName='start' 상태)
let [fade, setFade] = useState('')
useEffect(()=>{
// tab의 상태가 변할때 (클릭 후 다른탭 열리면) 0.1초 뒤 'end' className 바인딩
const fadeTimer = setTImeout(()=>{ setFade('end') }, 100)
return ()=>{
// 기존 fadeTimer 제거 후 class 빈 값으로 변경
clearTimeout(fadeTimer);
setFade('')
}
}, [tab])
return (
<div className={'start ' + fade}>
{ [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][탭] }
</div>
)
}
추가적으로 위와 같은 방식으로 Detail 컴포넌트 전체에도 fade효과를 넣어보았다!