tab은 버튼, 내용 이렇게 크게 두가지 영역으로 나누고,
0번째버튼->0번째내용
1번째버튼->1번째내용
2번째버튼->2번째내용
이런 구조가 된다. 리액트 환경에서는 어떻게 짤까.
우선, 보였다 사라졌다 하는 동적 UI 구성은 1. state를 생성해 스위치 처럼 쓴다
그리고 html을 해당 2. state의 값에 따라 조건식으로 보여주고
버튼을 누를 때 3. onClick 이벤트 안에 Tab setter함수를 제어해주면 될 것.
function Detail(){
let [tab, setTab] = useState(0);
function Detail(){
let [tab, setTab] = useState(0);
//tab 버튼영역
<Nav variant="tabs" defaultActiveKey="link0">
<Nav.Item>
<Nav.Link onClick={()=>{ setTab(0) }} eventKey="link0">버튼0</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link onClick={()=>{ setTab(1) }} eventKey="link1">버튼1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link onClick={()=>{ setTab(2) }} eventKey="link2">버튼2</Nav.Link>
</Nav.Item>
</Nav>
//tab 내용역역 - 컴포넌트로 삽입, props로 state전달
<Tab tab={tab}/>
}
Tab 컴포넌트 안에서 조건에 따라 보여질 내용이 달라지는데 html안에서는 조건식을 쓸수가 없다. 따라서 컴포넌트로 따로 구성해 삽입해준다.
function Tab({tab}){ //props 이런식으로 바로 state명으로 지정해 전달받을 수도 있음.
if(tab == 0){
return <div>내용0</div>
}else if(tab == 1){
return <div>내용1</div>
}else if(tab == 2){
return <div>내용2</div>
}
}
function Tab({tab}){
// if(tab == 0){
// return <div>내용0</div>
// }else if(tab == 1){
// return <div>내용1</div>
// }else if(tab == 2){
// return <div>내용2</div>
// }
return [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]
}
리액트 환경에서 transition은 어떻게 부여할까.
방금 만든 Tab UI에 서서히 등장하는 fade 효과를 추가해보자.
우선 css에
1. 처음(효과가 없을 때)에 해당되는 className 과
최종(효과가 생긴 후)에 해당되는 className을 생성해주고
transition을 걸어준다.
그리고 효과를 주려는 2. html요소에 최종에 해당되는 className을 state명으로서 지정해준다.
그리고 어떤 이벤트핸들러로서 작용되는 state, 위의 예제에서는 {tab}의 값이 변경될 때만 실행하는 구문으로서 추가해준다. 👉 3. useEffect(()=>{},{tab})
.start{ //처음
opacity: 0;
}
.end{ //최종
opacity: 1;
transition: opacity .5s;
}
function Tab({tab}){
let [fade, setFade] = useState('')
return (
<div className={'start ' + fade}> //`start + ${fade}`
{ [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab] }
</div>
)
}
function Tab({tab}){
let [fade, setFade] = useState('')
useEffect(()=>{
let a = setTimeout(()=>{ setFade('end') }, 300) //fade의 값을 end로
return ()=>{ //clean up 함수 (fade className을 떼었다 붙여야 하니까)
clearTimeout(a);
setFade('')
}
}, [tab])
return (
<div className={'start ' + fade}>
{ [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab] }
</div>
)
}
💡 setTimeout은 굳이 왜 쓸까?
이미 css에서 transition으로 속도감을 줬는데
굳이 useEffect구문안에서 setTimeout함수를 또 쓴 이유가 뭘까?
리액트 18버전 이상부터는 automatic batch 라는 기능이 생겼음.
state 변경함수들이 연달아서 여러개 처리되어야한다면
state 변경함수를 다 처리하고 마지막에 한 번만 재렌더링된다. (역시 효율적인 리액트)
그래서 'end' 로 변경하는거랑 ' ' 이걸로 변경하는거랑 약간 시간차를 둔 것.
만약 setTimout으로 시간차를 두지않았다면,
한번에 변경이 일어나 fade효과처럼 보이지않는다.
찾아보면 setTimeout 말고 flushSync() 이런거 쓰면 아예 automatic batching을 막아준다.