๋์์ธํ๊ณผ ์กธ์ ์ ์ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ค๋ฉด์, ์ ์ฒด ํ์ด์ง์ ์ํ ์์ฝ๋์ธ ์ ํ ์ ๋๋ฉ์ด์ ์ด ํ์ํ์ต๋๋ค.

์ฒ์ ์ ๊ทผ์ ๋จ์ํ ๋ค๋ฅธ ์์ฝ๋์ธ ์ ๋๋ฉ์ด์
์ฒ๋ผ ๋จ์ํ๊ฒ ์ ๊ทผํ์ต๋๋ค.
๋ชจ๋ ํ์ด์ง ์ปดํฌ๋ํธ๋ฅผ ํ ๋ฒ์ ์ ๋ถ ๋ง์ดํธํด๋๊ณ , ๊ฐ ์น์
์ max-width ๋ง ์กฐ์ ํ๋ฉด์ ์ด๋ฆฌ๊ณ ๋ซํ๋ ์ ๋๋ฉ์ด์
์ ๊ตฌํํ์ต๋๋ค.
๐ฉธ ์ฌ๊ฑด ํ์ฅ โ
๊ทธ๋ฐ๋ฐ ์ฌ๊ฑธ.. Lighthouse์์ DOM ์์๊ฐ 3,495๊ฐ๋ผ๋ ๊ฒฝ๊ณ ๊ฐ ๋จ๊ณ , TBT(Total Blocking Time)๋ ๋๊ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๋ ๊ณ์ ๋์ด๋๋ ํ์์ด ๋ฐ์ํ๋๊ฒ ์๋๊ฒ ์ต๋๊น?


๋ฌด์๋ณด๋ค ์ ๋ณด์ด๋ ํ์ด์ง๋ ๊ณ์ DOM ์์๋ก์จ ๋จ์์๋ค๋ ์ ์ด ๋ฌธ์ ์์ต๋๋ค.
์ ๋๋ฉ์ด์
์ด ๋๋๋ ์ปดํฌ๋ํธ๋ ์ธ๋ง์ดํธ ๋์ง ์์ผ๋๊น, ๋ธ๋ผ์ฐ์ ์
์ฅ์์๋ ๊ทธ๋ฅ ํ์ด์ง ์ฌ๋ฌ ๊ฐ๋ฅผ ๋์์ ๋๋ฆฌ๊ณ ์๋ ์
์ด์์ต๋๋ค.
์ ๋๋ฉ์ด์ ์ ์์ฐ์ค๋ฝ๊ฒ ์ ์งํ๋, ํ๋ฉด ๋ฐ๊นฅ์ผ๋ก ๋๊ฐ ํ์ด์ง๋ DOM ์์ ์น์๋ฒ๋ฆด ์ ์์๊น?
FramerMotion, React Spring ๋ฑ ์ฌ๋ฌ ์ ๋๋ฉ์ด์
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ดํด๋ดค์ง๋ง, ์์ฝ๋์ธ ์ ๋๋ฉ์ด์
ํ๋๋ฅผ ์ํด์ ๋ฒ๋ค ์ฌ์ด์ฆ๊ฐ ํฌ๊ธฐ๋ ํ๊ณ , ๋์์ด๋๊ฐ ๋ฑ ์ํ๋ ์ ๋๋ฉ์ด์
์ ๊ตฌํํ๊ธฐ๊ฐ ์ด๋ ค์ ์ต๋๋ค.
๊ฒฐ๊ตญ React Transition Group ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
ํ์ง๋ง, ๊ณต์๋ฌธ์๊ฐ ๋ถ์น์ ํด์ ๋ด๋ถ ๋์ ๋ฐฉ์์ ์ง์ ์ดํด๋ณด๊ณ , ์ด๋ป๊ฒ ์ ๋๋ฉ์ด์
์ด ์ข
๋ฃ๋ ์ดํ ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ ๋๋์ง ๋ค์ ๊ฑฐ๋ ค๋ดค์ต๋๋ค.
๐ต๏ธโโ๏ธ React Transition Group โ
React Transition Group์ ์ปดํฌ๋ํธ๊ฐ ๋ค์ด์ค๊ณ ๋๊ฐ ๋(๋ง์ดํธ/์ธ๋ง์ดํธ ์์ )์ ์ ํ์ ์ ์ํ ์ ์๋๋ก ์ฌ๋ฌ ๊ฐ๋จํ ์ปดํฌ๋ํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
React Transition Group์ React-Motion ๊ฐ์ ์ ๋๋ฉ์ด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋๋๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฒด๊ฐ ์คํ์ผ์ ์ง์ ์ ๋๋ฉ์ด์ ์ํค์ง๋ ์์ต๋๋ค.
๋์ ์, ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ ํ(transition)์ ๊ฐ ๋จ๊ณ ์ ๋ณด๋ฅผ ๋ ธ์ถํ๊ณ , ํด๋์ค ์ด๋ฆ์ ๋ถ์ด๊ฑฐ๋ ๋ผ๊ณ , ์์๋ค์ ๊ทธ๋ฃนํํ๊ณ , DOM์ ์ ์ ํ ์กฐ์ํด ์ค๋๋ค. ๋๋ถ์ ์ค์ ์๊ฐ์ ์ธ ์ ํ ์ ๋๋ฉ์ด์ ์ ๊ตฌํํ๋ ์์ ์ด ํจ์ฌ ์ฌ์์ง๋๋ค.
React Transition Group ๊ณต์ ๋ฌธ์๋ฅผ ๋ค์ด๊ฐ๋ณด๋ฉด ํฌ๊ฒ Transition, CSSTransition, SwitchTransition, TransitionGroup ๋ค ๊ฐ์ง ์ปดํฌ๋ํธ๋ฅผ ์ ๊ณตํ๋ค๊ณ ๋์์์ต๋๋ค.
์ด์ ๋ถํฐ ์ด ๋ค๊ฐ์ง ์ปดํฌ๋ํธ์ ๋ํด ํ๋์ฉ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1๏ธโฃ <Transition/> : ์ด ์์๋ฅผ ์ง๊ธ ๋ณด์ฌ์ค๊บผ์ผ? ์จ๊ธธ๊บผ์ผ? โ
<Transition/> ์ปดํฌ๋ํธ๋ React Transition Group ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋ ์ปดํฌ๋ํธ ์
๋๋ค.
์ด ์ปดํฌ๋ํธ๋ ์์ ์ปดํฌ๋ํธ๋ฅผ ์ง๊ธ ๋ณด์ฌ์ค๊บผ์ผ? ์จ๊ธธ๊บผ์ผ? ๋ผ๋ ์ํ๋ฅผ in prop ์ผ๋ก ๋ฐ์์, ์ปดํฌ๋ํธ์ ๋ผ์ดํ์ฌ์ดํด์ ์ํ๋จธ์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
โ๏ธ in: boolean โ
inprop ์ boolean ํ์ ์ผ๋ก,true๋ฉด ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ,false๋ฉด ์จ๊น๋๋ค.- ์ด ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก
<Transition/>์ ๋ด๋ถ์ ์ผ๋กentering,entered,exiting,exited๋ค ๊ฐ์ง ์ํ๋ก ์ ํ๋ฉ๋๋ค.
โ๏ธ mountOnEnter: boolean, unmountOnExit: boolean โ
mountOnEnter:in์ด ์ฒ์์ผ๋กtrue๊ฐ ๋๊ธฐ์ ์ ์ปดํฌ๋ํธ๋ฅผ ๋ง์ดํธํ์ง ์์ต๋๋ค.unmountOnExit:in์ดfalse๊ฐ ๋ ํ์ ์ปดํฌ๋ํธ๋ฅผ ์ธ๋ง์ดํธํฉ๋๋ค.
์ด ๋ ์ต์ ์ ์ฌ์ฉํ๋ฉด, ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ๋ณด์ผ ๋๋ง ๋ง์ดํธ๋๊ณ , ํ๋ฉด์์ ์ฌ๋ผ์ง ๋ ์ธ๋ง์ดํธ ๋๋๋ก ํ ์ ์์ต๋๋ค.
โ๏ธ appear: boolean โ
- ์ฒ์ ๋ง์ดํธ๋ ๋๋ ๋ฑ์ฅ ์ ๋๋ฉ์ด์
์ ์ ์ฉํ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. (๊ธฐ๋ณธ๊ฐ์
false)
โ๏ธ enter: boolean, exit: boolean โ
- ๊ฐ ์ ๋๋ฉ์ด์ ์ ์์ ๋นํ์ฑํ ํ ์ ์์ต๋๋ค
enter : false์ธ ๊ฒฝ์ฐ ๋ค์ด์ฌ๋ ์ ๋๋ฉ์ด์ ์์ด ๋ฐ๋กentered์ํ๋ก ์ ์ด๋ฉ๋๋ค.exit : false์ธ ๊ฒฝ์ฐ ๋๊ฐ๋ ์ ๋๋ฉ์ด์ ์์ด ๋ฐ๋กexited์ํ๋ก ์ ์ด๋ฉ๋๋ค.
โ๏ธ timeout: number ์ addEndListener โ
- React Transition Group ์ ์ ๋๋ฉ์ด์ ์ด ์ธ์ ๋๋ฌ๋์ง ์์์ผ ๋ค์ ์ํ๋ก ์ ์ด ํ ์ ์์ต๋๋ค
timeout : number: ์ง์ ๋ ms ์ดํ์ ์ ๋๋ฉ์ด์ ์ด ๋๋ฌ๋ค๊ณ ๊ฐ์ฃผํฉ๋๋ค.addEndListener(node, done): DOM ๋ ธ๋์ ์ค์ ์ ๋๋ฉ์ด์ ์๋ฃ ์ด๋ฒคํธ๋ฅผ ์ก์์done()์ ํธ์ถํด์ฃผ๋ ๋ฐฉ์์ด๋น๋ค.
<Transition
in={show}
addEndListener={(node, done) => {
node.addEventListener("transitioned", done);
}}
/>๐ ์ํ ์ ์ด โ
๊ฒฐ๊ตญ <Transition/> ์ปดํฌ๋ํธ์ ํต์ฌ์ ๊ฐ props ์ ๋ฐ๋ฅธ ์ํ ์ ์ด์
๋๋ค.
ํ
์คํธ๋ก๋ง ์ค๋ช
ํ๋ฉด ์ ์ดํด๊ฐ ์๋๋... ์ํ ์ ์ด ๋ค์ด์ด๊ทธ๋จ์ ๋ณด๋ฉด ์ดํด๊ฐ ์ฝ์ต๋๋ค
์ฌ์ค ํ๋ก ํธ๊ฐ์๊ฑฐ ์ข์ํ๋ ์ด์ ๋ ์ด๋ ๊ฒ ์๊ฐ์ ์ผ๋ก ๋ญ๊ฐ ์ ๋ฆฌํ๋๊ฒ ์ดํด๊ฐ ์ฝ๊ณ ์ฌ๋ฐ์ด์ ๊ทธ๋ ์ต๋๋ค ใ
ใ

๐โโ๏ธ ์ํ ์ ์ด ๋ค์ด์ด๊ทธ๋จ์์ [] ๋ ๋ญ๊ฐ์? - Guard
[] ํ์๋ ๊ฐ๋(Guard) ์กฐ๊ฑด์ ์๋ฏธํฉ๋๋ค.
๊ฐ๋ ์กฐ๊ฑด์ ์ํ ์ ์ด๊ฐ ๋ฐ์ํ๊ธฐ ์ํ ์ถ๊ฐ์ ์ธ ์กฐ๊ฑด์ ๋ํ๋
๋๋ค.
์๋ฅผ ๋ค์ด, ๊ฐ์ฅ ์์ ๋ณด์ด๋ [mountOnEnter === true] ๋ ์ด๊ธฐ ์ํ์์ mountOnEnter props ๊ฐ true ์ผ ๋๋ง unmounted ์ํ๋ก ์ ์ด๋๋ค๋ ์๋ฏธ์
๋๋ค.
2๏ธโฃ <CSSTransition/> : CSS ํด๋์ค ์ด๋ฆ ์์์ ๋ถ์ฌ์ค๊ฒ ~ โ
<CSSTransition/> ์ปดํฌ๋ํธ๋ <Transition/> ์ปดํฌ๋ํธ๋ฅผ ํ์ฅํ ์ปดํฌ๋ํธ๋ก, CSS ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์
์ ์ ์ดํ ์ ์๋๋ก ๋์์ค๋๋ค.
์ฐจ์ด์ ์ ํ๋์
๋๋ค. <Transition/> ์ปดํฌ๋ํธ๋ ํ์ด๋ฐ๋ง ์ ์ดํ๊ณ ์คํ์ผ์ ์ง์ on* ์ฝ๋ฐฑ props ๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ ์ ์ดํด์ผ ํ์ง๋ง, <CSSTransition/> ์ปดํฌ๋ํธ๋ ๊ฐ ์ํ์ ๋ง๋ CSS ํด๋์ค ์ด๋ฆ์ ์๋์ผ๋ก ์ถ๊ฐ/์ ๊ฑฐ ํด์ค๋ค๋ ์ ์
๋๋ค.
๊ฐ๋ฐ์๋ ๊ทธ๋ฅ classNames prefix ๋ฅผ ๊ธฐ์ค์ผ๋ก CSS ๋ง ์ ์ํด๋๋ฉด ๋ฉ๋๋ค.
<CSSTransition in={show} timeout={300} classNames="prefix" mountOnEnter unmountOnExit>
<Component />
</CSSTransition>์ด๋ ๊ฒ๋ง ์จ๋๋ฉด, ์ํ ์ ์ด์ ๋ฐ๋ผ ๋ค์๊ณผ ๊ฐ์ ํด๋์ค๋ค์ด ์๋์ผ๋ก ๋ถ์ต๋๋ค
- Enter ์
prefix-enter- ์ดํ ๋ฐ๋ก
prefix-enter-active - ์๋ฃ ํ
prefix-enter-done
- Exit ์
prefix-exit- ์ดํ ๋ฐ๋ก
prefix-exit-active - ์๋ฃ ํ
prefix-exit-done
โ๏ธ appear: boolean ์ ๋ฐ๋ฅธ classNames โ
appear:true ๋ฅผ ์ค์ ํ ๊ฒฝ์ฐ, ๋ง์ดํธ ์ด๊ธฐ์๋ prefix-appear, prefix-appear-active, prefix-appear-done ํด๋์ค๊ฐ ์ ์ฉ ๋ฉ๋๋ค.
์ด๋ฅผ ํตํด ์ฒซ ๋ฑ์ฅ ์ ๋๋ฉ์ด์ ์ ์ชผ๊ธ ๋ค๋ฅด๊ฒ ์ค ์๋ ์์ต๋๋ค.
๐คจ ์ ํด๋์ค๊ฐ ๋๋ฒ์ ๋๋ ์ ๋ถ์ง (reflow ํธ๋ฆญ) โ
์ ๋๋ฉ์ด์
์ ์์ฐ์ค๋ฝ๊ฒ ์์ํ๋ ค๋ฉด ์ด๊ธฐ ์ํ ํด๋์ค ์ ํ์ฑ ์ํ ํด๋์ค ๋ฅผ ์๋ก ๋ค๋ฅธ ํ๋ ์์ ๋ถ์ฌ์ผ ํฉ๋๋ค.
<CSSTransition/> ์ปดํฌ๋ํธ๋ ๋๋ต ์ด๋ฐ์์ผ๋ก ๋์ํฉ๋๋ค
onEnter์์ ์prefix-enterํด๋์ค๋ฅผ ๋ถ์ฌ๋๋ค- ๋ค์ ํ๋ ์์์ ๊ฐ์ ๋ก ํ๋ฒ reflow ๋ฅผ ๋ฐ์์ํจ๋ค (
node.offset*๊ฐ์ ์ฝ๋๋ก ๊ฐ์ ๋ก layout ์ ์ฝ์ด ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฌ ์คํ์ผ์ ๊ณ์ฐํ๊ฒ ๋ง๋ญ๋๋ค) - ๊ทธ ๋ค์์
prefix-enter-activeํด๋์ค๋ฅผ ๋ถ์ธ๋ค (์ต์ข ์คํ์ผ)
INFO
๋๊ฐ์ ํด๋์ค๋ฅผ ๋์์ ๋ถ์ด๋ฉด, ๋ธ๋ผ์ฐ์ ๊ฐ ์์ ์ํ๋ฅผ ๋ชป ์ก๊ณ ๊ทธ๋ฅ ์ต์ข ์ํ๋ก ๋ฐ๋ก ๋์ด๊ฐ ๋ฒ๋ฆฌ๋ ๊ฒฝ์ฐ๊ฐ ์์ด์ ์ผ๋ถ๋ฌ reflow ๋ก ํ์ด๋ฐ์ ๋๋ ์ค๋๋ค!
exit ๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค
3๏ธโฃ <TransitionGroup/> : ์ฌ๋ฌ ์ปดํฌ๋ํธ์ ์
์ฅ๊ณผ ํด์ฅ์ ๊ด๋ฆฌํด์คญ โ
<Transition/> ๊ณผ <CSSTransition/> ์ปดํฌ๋ํธ๋ ํ๋์ ์ปดํฌ๋ํธ๊ฐ ๋ค์ด์ค๊ณ ๋๊ฐ๋ ์๊ฐ์ ๊ด๋ฆฌํฉ๋๋ค.
๊ทผ๋ฐ ์ค์ ์ ๋๋ฉ์ด์
์์๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๋์์ ๋ค์ด์ค๊ณ ๋๊ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
์ฌ๋ฌ ์ปดํฌ๋ํธ์ ์ง์
, ํด์ฅ ํ์ด๋ฐ์ ๊ด๋ฆฌํด์ค์ผ ํ๋๊ฑฐ์ฃ
์ด๊ฑธ ํด๊ฒฐํด์ฃผ๋ ์น๊ตฌ๊ฐ <TransitionGroup/> ์ปดํฌ๋ํธ์
๋๋ค.
<TransitionGroup component={null}>
{items.map((item) => {
return (
<CSSTransition
key={item.id}
timeout={300}
classNames="prefix"
mountOnEnter={true}
unmountOnExit={true}
>
<ItemComponent item={item} />
</CSSTransition>
);
})}
</TransitionGroup>โ๏ธ key โ
<TransitionGroup/> ์ปดํฌ๋ํธ๋ key ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ด๋ค ์ปดํฌ๋ํธ๊ฐ ์๋ก ๋ค์ด์๋์ง, ์ด๋ค ์ปดํฌ๋ํธ๊ฐ ๋๊ฐ๋์ง๋ฅผ ํ๋จํฉ๋๋ค.
- TransitionGroup ์ children ์ key ๋ชฉ๋ก์ ๊ธฐ์ตํด ๋ก๋๋ค.
- ๋ค์ ๋ ๋๋ง์ key ์ ๋ชฉ๋ก์ด ๋ฐ๋์๋์ง ๋น๊ตํฉ๋๋ค.
- ์๋ก ์๊ธด key : ์๋ก์ด children ์ปดํฌ๋ํธ๊ฐ ๋ค์ด์จ ๊ฒ์ผ๋ก ํ๋จํ๊ณ
in=true๋ก ์ค์ ํด์ enter ์ ๋๋ฉ์ด์ ์ ์์ํฉ๋๋ค. - ์์ด์ง key : ์ฌ๋ผ์ง children ์ปดํฌ๋ํธ๊ฐ ๋๊ฐ ๊ฒ์ผ๋ก ํ๋จํ๊ณ DOM ์์ ๋ฐ๋ก ์ ๊ฑฐํ์ง ์๊ณ ,
in=false๋ฅผ ์ฃผ๋ฉด์ exit ์ ๋๋ฉ์ด์ ์ ๋จผ์ ์คํํฉ๋๋ค. (์ฌ๋ผ์ง๋ ์ ๋ฅผ ๋ฐ๋ก ์์ง์ฐ๊ณ ํด์ฅ ์ ๋๋ฉ์ด์ ์ ์คํํ ์๊ฐ์ ์ค)
- ์๋ก ์๊ธด key : ์๋ก์ด children ์ปดํฌ๋ํธ๊ฐ ๋ค์ด์จ ๊ฒ์ผ๋ก ํ๋จํ๊ณ
- exit ์ ๋๋ฉ์ด์ ์ด ๋๋๋ ์์ ์๋ง state ์์ ์ ๊ฑฐํด์ ์ค์ DOM ์์๋ ์ ๊ฑฐํฉ๋๋ค.
โ๏ธ component โ
๊ธฐ๋ณธ์ ์ผ๋ก <TransitionGroup/> ์ปดํฌ๋ํธ๋ <div> ๋ํผ๋ฅผ ์ฌ์ฉํฉ๋๋ค. null ์ ์ฃผ๋ฉด ์์๋ง ๋ ๋๋งํ ์ ์์ต๋๋ค.
4๏ธโฃ <SwitchTransition/> : ํ ๋ฒ์ ํ๋์ ์ปดํฌ๋ํธ๋ง ๋ณด์ฌ์ค๊บผ์ โ
<SwitchTransition/> ์ปดํฌ๋ํธ๋ ํญ์ ๋ฑ ํ๋์ ์์ ์ปดํฌ๋ํธ๊ฐ ์กด์ฌํ๊ณ ๊ทธ๊ฑธ ๋ฐ๊ฟ ๋ ์ ๋๋ฉ์ด์
ํ๊ณ ์ถ๋ค๋ ์ํฉ์ ์ฐ์ด๋ ์ปดํฌ๋ํธ์
๋๋ค.
์๋ฅผ๋ค์ด, ํ์ฅ ์ฌ๋ผ์ง๊ณ ๋ค๋ฅธ ํ์ฅ์ด ๋ํ๋๋ ์ฌ๋ผ์ด๋์ผ ๊ฐ์ ์ํฉ์ด ์๊ฒ ๋ค์
์ด ์ปดํฌ๋ํธ๋ mode ๋ผ๋ props ๋ก ์ ํ ์์๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
โ๏ธ mode : "out-in" | "in-out" โ
out-in- ํ์ฌ ์ปดํฌ๋ํธ์ exit ์ ๋๋ฉ์ด์ ์ ์์ ํ ๋๋ด๊ณ
- ๋ค ์ฌ๋ผ์ง ๋ค์ ์๋ก์ด ์์์ด enter ์ ๋๋ฉ์ด์ ์ผ๋ก ๋ฑ์ฅํฉ๋๋ค.
in-out- ์๋ก์ด ์์์ด enter ์ ๋๋ฉ์ด์ ์ผ๋ก ๋จผ์ ๋ค์ด์ค๊ณ
- ๋ค ์๋ฆฌ์ก์ ๋ค์์ ๊ธฐ์กด ์์์๊ฒ exit ์ ๋๋ฉ์ด์ ์ ์คํํฉ๋๋ค.
๐ฒ (์คํ) ๋ชจ๋ฐ์ผ ํ๋ฉด ์ ํ ์ ๋๋ฉ์ด์ ์ ๋ง๋ค์ด๋ณด์ โ
์ด์ ๊น์ง ์ดํด๋ณธ ๋ด์ฉ์ ๋ฐํ์ผ๋ก, ๋ชจ๋ฐ์ผ ํ๋ฉด ์ ํ ์ ๋๋ฉ์ด์
์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.
์๊ตฌ์ฌํญ
- ์๋ก์ด ํ๋ฉด์ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฌ๋ผ์ด๋ ์ธ
- ๊ธฐ์กด ํ๋ฉด์ ์ผ์ชฝ์ผ๋ก ์ฌ๋ผ์ด๋ ์์
- ๋ ํ๋ฉด์ด ๋์์ ์ ํ๋จ
์ฌ๋ฌ ์์ ์ปดํฌ๋ํธ๊ฐ ๋์์ ๋ค์ด์ค๊ณ ๋๊ฐ๋ ์ํฉ์ด๋ฏ๋ก <TransitionGroup/> ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๊ฒ ๋ค์
import { TransitionGroup, CSSTransition } from "react-transition-group";
import { Routes, Route, useLocation } from "react-router-dom";
function App() {
const location = useLocation();
return (
<TransitionGroup className="page-wrapper">
<CSSTransition
key={location.key}
classNames="slide"
timeout={300}
mountOnEnter
unmountOnExit
>
<Routes location={location}>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
{/* ... */}
</Routes>
</CSSTransition>
</TransitionGroup>
);
}โ ๏ธ ์ฌ๊ธฐ์ ์ค์ํ ํฌ์ธํธ โ
key={location.key}: ๋ผ์ฐํ ํ ๋ ๋ง๋ค key๊ฐ ๋ฐ๋๋ฏ๋ก,<TransitionGroup/>์ ์ฅ์์ "์ด์ ํ๋ฉด ํ๋", "์ ํ๋ฉด ํ๋" ๋ผ๋ ๋ ์ปดํฌ๋ํธ๋ฅผ ๋์์ ๊ด๋ฆฌ ํ ์ ์๊ฒ ํฉ๋๋คmountOnEnter,unmountOnExit: ํ์ฌ ๋ณด์ฌ์ค ํ๋ฉด๋ง DOM ์ ๋จ๊ธฐ๊ณ , ์ด์ ํ๋ฉด์ ์ ๋๋ฉ์ด์ ์ด ๋๋๋ ์๊ฐ ์ธ๋ง์ดํธ ๋๋๋ก ํฉ๋๋ค
๐จ CSS ๋ฅผ ์์ฑํด๋ณด์ โ
์ด์ prefix ์ ๋ฐ๋ฅธ CSS ๋ง ์์ฑํด์ฃผ๋ฉด ๋ฉ๋๋ค
/* ๋ถ๋ชจ: ๊ฒน์ณ์ ๋ณด์ฌ์ค ์ ์๋๋ก relative */
.page-wrapper {
position: relative;
overflow: hidden;
}
/* ๊ฐ ํ์ด์ง๋ ๊ฒน์น ์ ์๋๋ก absolute */
.page-wrapper > * {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* Enter (์ ํ๋ฉด์ด ์ค๋ฅธ์ชฝ์์ ๋ค์ด์ด) */
.slide-enter {
transform: translateX(100%); /* ์์: ์ค๋ฅธ์ชฝ ๋ฐ๊นฅ */
}
.slide-enter-active {
transform: translateX(0%);
transition: transform 300ms ease;
}
.slide-enter-done {
transform: translateX(0%);
}
/* Exit (์ด์ ํ๋ฉด์ด ์ผ์ชฝ์ผ๋ก ๋ฐ๋ ค๋๊ฐ) */
.slide-exit {
transform: translateX(0%); /* ์์: ํ์ฌ ์์น */
}
.slide-exit-active {
transform: translateX(-100%); /* ์ผ์ชฝ ๋ฐ๊นฅ์ผ๋ก ๋๊ฐ */
transition: transform 300ms ease;
}
.slide-exit-done {
transform: translateX(-100%);
}๐ ์ด๋ป๊ฒ ๋์ํ๋? โ
- ๋ผ์ฐํธ ๋ณ๊ฒฝ =>
<CSSTransition key={...}>๊ฐ ์๋ก์ด ํ๋ฉด์ ํ๋ ๋ ๋ ๋ (TransitionGroup์ด ์ด์ ํ๋ฉด์ in={false}, ์ ํ๋ฉด์ in={true} ์ํ๋ก ๊ด๋ฆฌ) - ์ด์ ํ๋ฉด์๋
.slide-exit/ ์ ํ๋ฉด์๋.slide-enterํด๋์ค๊ฐ ๊ฐ๊ฐ ๋ค์ด๊ฐ - ๋ค์ animation frame์์
.slide-exit-active,.slide-enter-activeํด๋์ค๊ฐ ๋ถ์ผ๋ฉด์- ์ด์ ํ๋ฉด: translateX(-100%)๋ก ์ผ์ชฝ์ผ๋ก ๋ฐ๋ ค๋๊ฐ๊ณ
- ์ ํ๋ฉด: translateX(0)๊น์ง ์ค๋ฅธ์ชฝ์์ ์ฌ๋ผ์ด๋ ์ธ
- ์ฝ 300ms ๋ค transition์ด ๋๋๋ฉด
- ์ด์ ํ๋ฉด์ onExited => ์ธ๋ง์ดํธ
- ์ ํ๋ฉด์ .slide-enter-done ์ํ๋ก ์ ์์ ์ผ๋ก ๋จ์