<ViewTransition>
<ViewTransition>์ ์ฌ์ฉํ๋ฉด Transition ๋ด๋ถ์์ ์
๋ฐ์ดํธ๋๋ ์๋ฆฌ๋จผํธ์ ์ ๋๋ฉ์ด์
์ ์ ์ฉํ ์ ์์ต๋๋ค.
import {ViewTransition} from 'react';
<ViewTransition>
<div>...</div>
</ViewTransition>- ๋ ํผ๋ฐ์ค
- ์ฌ์ฉ๋ฒ
- enter/exit์์ ์๋ฆฌ๋จผํธ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
- ๊ณต์ ์๋ฆฌ๋จผํธ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
- ๋ชฉ๋ก์์ ํญ๋ชฉ ์์ ๋ณ๊ฒฝ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
- Suspense ์ฝํ ์ธ ์์ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
- ์ ๋๋ฉ์ด์ ์ ์ธํ๊ธฐ
- ์ ๋๋ฉ์ด์ ์ปค์คํฐ๋ง์ด์ง
- ํ์ ์ผ๋ก ์ ๋๋ฉ์ด์ ์ปค์คํฐ๋ง์ด์งํ๊ธฐ
- View Transition ์ง์ ๋ผ์ฐํฐ ๊ตฌ์ถํ๊ธฐ
- ๋ฌธ์ ํด๊ฒฐ
๋ ํผ๋ฐ์ค
<ViewTransition>
์๋ฆฌ๋จผํธ๋ฅผ <ViewTransition>์ผ๋ก ๊ฐ์ธ๋ฉด Transition ๋ด๋ถ์์ ์
๋ฐ์ดํธํ ๋ ์ ๋๋ฉ์ด์
์ ์ ์ฉํ ์ ์์ต๋๋ค. React๋ ๋ค์ ํด๋ฆฌ์คํฑ์ ์ฌ์ฉํ์ฌ View Transition์ด ์ ๋๋ฉ์ด์
์ ํ์ฑํ๋๋์ง ํ๋จํฉ๋๋ค.
enter: ํด๋น Transition์์ViewTransition์์ฒด๊ฐ ์ฝ์ ๋๋ฉด ํ์ฑํ๋ฉ๋๋ค.exit: ํด๋น Transition์์ViewTransition์์ฒด๊ฐ ์ญ์ ๋๋ฉด ํ์ฑํ๋ฉ๋๋ค.update:ViewTransition๋ด๋ถ์์ React๊ฐ ์ํํ๋ DOM ๋ณ๊ฒฝ(์: ํ๋กํผํฐ ๋ณ๊ฒฝ)์ด ์๊ฑฐ๋ ์ธ์ ํ ํ์ ์๋ฆฌ๋จผํธ์ ์ํฅ์ผ๋กViewTransition๊ฒฝ๊ณ ์์ฒด์ ํฌ๊ธฐ๋ ์์น๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ ํ์ฑํ๋ฉ๋๋ค. ์ค์ฒฉ๋ViewTransition์ด ์์ผ๋ฉด ๋ณ๊ฒฝ์ด ๋ถ๋ชจ๊ฐ ์๋ ํด๋น ํญ๋ชฉ์ ์ ์ฉ๋ฉ๋๋ค.share: ์ด๋ฆ์ด ์ง์ ๋ViewTransition์ด ์ญ์ ๋ ์๋ธํธ๋ฆฌ ๋ด๋ถ์ ์๊ณ ๊ฐ์ ์ด๋ฆ์ ๊ฐ์ง ๋ค๋ฅธ ์ด๋ฆ ์๋ViewTransition์ด ๊ฐ์ Transition์์ ์ฝ์ ๋ ์๋ธํธ๋ฆฌ์ ์ผ๋ถ์ธ ๊ฒฝ์ฐ ๊ณต์ ์๋ฆฌ๋จผํธ Transition์ ํ์ฑํ๋ฉฐ, ์ญ์ ๋ ๊ฒ์์ ์ฝ์ ๋ ๊ฒ์ผ๋ก ์ ๋๋ฉ์ด์ ๋ฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก <ViewTransition>์ ๋ถ๋๋ฌ์ด ํฌ๋ก์ค ํ์ด๋(๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ View Transition)๋ก ์ ๋๋ฉ์ด์
๋ฉ๋๋ค. <ViewTransition> ์ปดํฌ๋ํธ์ View Transition ํด๋์ค๋ฅผ ์ ๊ณตํ์ฌ ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ต๋๋ค. ๊ฐ ํธ๋ฆฌ๊ฑฐ ์ ํ์ ๋ํด ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ต๋๋ค(View Transition ์คํ์ผ๋ง ์ฐธ๊ณ ).
์์ธํ ์ดํด๋ณด๊ธฐ
๋ด๋ถ์ ์ผ๋ก React๋ <ViewTransition> ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ค์ฒฉ๋ ๊ฐ์ฅ ๊ฐ๊น์ด DOM ๋
ธ๋์ ์ธ๋ผ์ธ ์คํ์ผ์ view-transition-name์ ์ ์ฉํฉ๋๋ค. <ViewTransition><div /><div /></ViewTransition>์ฒ๋ผ ์ฌ๋ฌ ํ์ DOM ๋
ธ๋๊ฐ ์์ ๊ฒฝ์ฐ, React๋ ๊ฐ ๋
ธ๋์ ์ด๋ฆ์ด ๊ณ ์ ํ๋๋ก ์ ๋ฏธ์ฌ๋ฅผ ์ถ๊ฐํ์ง๋ง, ๊ฐ๋
์ ์ผ๋ก๋ ๋์ผํ ์ ํ์ ์ํ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํฉ๋๋ค.
React๋ ๋ด๋ถ์ ์ผ๋ก startViewTransition์ ์์ฒด์ ์ผ๋ก ํธ์ถํ๋ฏ๋ก ์ง์ ํธ์ถํด์๋ ์๋ฉ๋๋ค. ์ค์ ๋ก ํ์ด์ง์์ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ ์ฝ๋๊ฐ ViewTransition์ ์คํํ๊ณ ์๋ค๋ฉด React๊ฐ ์ด๋ฅผ ์ค๋จํฉ๋๋ค. ๋ฐ๋ผ์ React ์์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ์กฐ์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๊ณผ๊ฑฐ์ ViewTransition์ ํธ๋ฆฌ๊ฑฐํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ์์๋ค๋ฉด ๋ด์ฅ ๋ฐฉ๋ฒ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๋ค๋ฅธ React ViewTransition์ด ์ด๋ฏธ ์คํ ์ค์ด๋ผ๋ฉด, React๋ ๊ทธ๊ฒ๋ค์ ์๋ฃํ ๋๊น์ง ๋ค์ ์ ํ์ ์์ํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ค์ํ ์ ์ ์ฒซ ๋ฒ์งธ ์ ํ์ด ์งํ๋๋ ๋์ ์ฌ๋ฌ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ๋ฉด, ๊ทธ ์ ๋ฐ์ดํธ๋ค์ ๋ชจ๋ ํ๋๋ก ๋ฌถ์ฌ ์ฒ๋ฆฌ๋๋ค๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด A์์ B๋ก ์ด๋ํ๋ ์ ํ์ ์์ํ๋ค๊ณ ๊ฐ์ ํฉ์๋ค. ๊ทธ ์ฌ์ด์ C๋ก ๊ฐ๋ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ๊ณ ๋ค์ D๋ก ๊ฐ๋ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, ์ฒซ ๋ฒ์งธ A->B ์ ๋๋ฉ์ด์ ์ด ๋๋ ํ ๋ค์ ์ ๋๋ฉ์ด์ ์ B์์ D๋ก ์ ํ๋ฉ๋๋ค.
getSnapshotBeforeUpdate ์๋ช
์ฃผ๊ธฐ๋ startViewTransition ์ ์ ํธ์ถ๋๊ณ ์ผ๋ถ view-transition-name์ ๋์์ ์
๋ฐ์ดํธ๋ฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ React๋ startViewTransition์ ํธ์ถํฉ๋๋ค. updateCallback ๋ด๋ถ์์ React๋ ๋ค์์ ์ํํฉ๋๋ค.
- DOM์ ๋ณ๊ฒฝ์ ์ ์ฉํ๊ณ
useInsertionEffect๋ฅผ ํธ์ถํฉ๋๋ค. - ํฐํธ๊ฐ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
- componentDidMount, componentDidUpdate, useLayoutEffect, refs๋ฅผ ํธ์ถํฉ๋๋ค.
- ๋๊ธฐ ์ค์ธ ํ์์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
- ๊ทธ๋ฐ ๋ค์ React๋ ๋ ์ด์์์ ๋ณ๊ฒฝ ์ฌํญ์ ์ธก์ ํ์ฌ ์ด๋ค ๊ฒฝ๊ณ๊ฐ ์ ๋๋ฉ์ด์ ๋์ด์ผ ํ๋์ง ํ์ธํฉ๋๋ค.
startViewTransition์ ready Promise๊ฐ ํด๊ฒฐ๋ ์ดํ, React๋ view-transition-name์ ๋๋๋ฆฝ๋๋ค. ๊ทธ ๋ค์ React๋ onEnter, onExit, onUpdate, onShare ์ฝ๋ฐฑ๋ค์ ํธ์ถํ์ฌ ์ ๋๋ฉ์ด์
์ ๋ํด ์๋์ผ๋ก ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ ์ ์ด๋ฅผ ํ ์ ์๋๋ก ํฉ๋๋ค. ์ด ํธ์ถ์ ๋ด์ฅ๋ ๊ธฐ๋ณธ ์ ๋๋ฉ์ด์
์ด ์ด๋ฏธ ๊ณ์ฐ๋ ์ดํ์ ์ด๋ฃจ์ด์ง๋๋ค.
์ด ์ํ์ค ์ค๊ฐ์ flushSync๊ฐ ๋ฐ์ํ๋ฉด ๋๊ธฐ์ ์ผ๋ก ์๋ฃ๋์ด์ผ ํ๋ ํน์ฑ ๋๋ฌธ์ React๋ ํด๋น Transition์ ๊ฑด๋๋๋๋ค.
startViewTransition์ finished Promise๊ฐ ํด๊ฒฐ๋ ์ดํ์ React๋ useEffect๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด useEffect๊ฐ ์ ๋๋ฉ์ด์
์ฑ๋ฅ์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ๋ฐฉ์งํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ด ๋ฐ๋์ ๋ณด์ฅ๋๋ ๊ฒ์ ์๋๋๋ค. ๋ง์ฝ ์ ๋๋ฉ์ด์
์ด ์คํ๋๋ ๋์ค์ ๋ค๋ฅธ setState๊ฐ ๋ฐ์ํ๋ฉด, ์์ฐจ์ ๋์ ๋ณด์ฅ์ ์ ์งํ๊ธฐ ์ํด useEffect๋ฅผ ๋ ์ผ์ฐ ํธ์ถํด์ผ ํ ์๋ ์์ต๋๋ค.
Props
๊ธฐ๋ณธ์ ์ผ๋ก <ViewTransition>์ ๋ถ๋๋ฌ์ด ํฌ๋ก์ค ํ์ด๋๋ก ์ ๋๋ฉ์ด์
๋ฉ๋๋ค. ์ด๋ฌํ ํ๋กํผํฐ๋ก ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์ฆํ๊ฑฐ๋ ๊ณต์ ์๋ฆฌ๋จผํธ Transition์ ์ง์ ํ ์ ์์ต๋๋ค.
- optional
enter: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. โenterโ๊ฐ ํ์ฑํ๋ ๋ ์ ์ฉํ View Transition ํด๋์ค์ ๋๋ค. - optional
exit: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. โexitโ์ด ํ์ฑํ๋ ๋ ์ ์ฉํ View Transition ํด๋์ค์ ๋๋ค. - optional
update: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. โupdateโ๊ฐ ํ์ฑํ๋ ๋ ์ ์ฉํ View Transition ํด๋์ค์ ๋๋ค. - optional
share: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. ๊ณต์ ์๋ฆฌ๋จผํธ๊ฐ ํ์ฑํ๋ ๋ ์ ์ฉํ View Transition ํด๋์ค์ ๋๋ค. - optional
default: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. ๋ค๋ฅธ ์ผ์นํ๋ ํ์ฑํ ํ๋กํผํฐ๊ฐ ์์ ๋ ์ฌ์ฉ๋๋ View Transition ํด๋์ค์ ๋๋ค. - optional
name: ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด. ๊ณต์ ์๋ฆฌ๋จผํธ transition์ ์ฌ์ฉ๋๋ View Transition์ ์ด๋ฆ์ ๋๋ค. ์ ๊ณต๋์ง ์์ผ๋ฉด React๋ ์์์น ๋ชปํ ์ ๋๋ฉ์ด์ ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๊ฐ View Transition์ ๋ํด ๊ณ ์ ํ ์ด๋ฆ์ ์ฌ์ฉํฉ๋๋ค.
์ฝ๋ฐฑ
์ด ์ฝ๋ฐฑ์ ์ฌ์ฉํ๋ฉด animate API๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์ ์ ๋ช ๋ น์ ์ผ๋ก ์กฐ์ ํ ์ ์์ต๋๋ค.
- optional
onEnter: ํจ์. React๋ โenterโ ์ ๋๋ฉ์ด์ ํ์onEnter๋ฅผ ํธ์ถํฉ๋๋ค. - optional
onExit: ํจ์. React๋ โexitโ ์ ๋๋ฉ์ด์ ํ์onExit๋ฅผ ํธ์ถํฉ๋๋ค. - optional
onShare: ํจ์. React๋ โshareโ ์ ๋๋ฉ์ด์ ํ์onShare๋ฅผ ํธ์ถํฉ๋๋ค. - optional
onUpdate: ํจ์. React๋ โupdateโ ์ ๋๋ฉ์ด์ ํ์onUpdate๋ฅผ ํธ์ถํฉ๋๋ค.
๊ฐ ์ฝ๋ฐฑ์ ๋ค์์ ์ธ์๋ก ๋ฐ์ต๋๋ค.
element: ์ ๋๋ฉ์ด์ ๋ DOM ์๋ฆฌ๋จผํธ์ ๋๋ค.types: ์ ๋๋ฉ์ด์ ์ ํฌํจ๋ Transition ํ์ ์ ๋๋ค.
View Transition ํด๋์ค
View Transition ํด๋์ค๋ ViewTransition์ด ํ์ฑํ๋ ๋ Transition ์ค์ React๊ฐ ์ ์ฉํ๋ CSS ํด๋์ค ์ด๋ฆ์ ๋๋ค. ๋ฌธ์์ด ๋๋ ๊ฐ์ฒด์ผ ์ ์์ต๋๋ค.
string: ํ์ฑํ๋ ๋ ์์ ์๋ฆฌ๋จผํธ์ ์ถ๊ฐ๋๋class์ ๋๋ค.'none'์ด ์ ๊ณต๋๋ฉด ํด๋์ค๊ฐ ์ถ๊ฐ๋์ง ์์ต๋๋ค.object: ์์ ์๋ฆฌ๋จผํธ์ ์ถ๊ฐ๋๋ ํด๋์ค๋addTransitionType์ผ๋ก ์ถ๊ฐ๋ View Transition ํ์ ๊ณผ ์ผ์นํ๋ ํค์ ๋๋ค. ๊ฐ์ฒด๋ ์ผ์นํ๋ ํ์ ์ด ์์ ๋ ์ฌ์ฉํdefault๋ ์ง์ ํ ์ ์์ต๋๋ค.
๊ฐ 'none'์ ํน์ ํธ๋ฆฌ๊ฑฐ์ ๋ํด View Transition์ด ํ์ฑํ๋์ง ์๋๋ก ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
View Transition ์คํ์ผ๋ง
<ViewTransition>์ ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์ฆํ๋ ค๋ฉด ํ์ฑํ ํ๋กํผํฐ ์ค ํ๋์ View Transition ํด๋์ค๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. View Transition ํด๋์ค๋ ViewTransition์ด ํ์ฑํ๋ ๋ React๊ฐ ์์ ์๋ฆฌ๋จผํธ์ ์ ์ฉํ๋ CSS ํด๋์ค ์ด๋ฆ์
๋๋ค.
์๋ฅผ ๋ค์ด โenterโ ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์ฆํ๋ ค๋ฉด enter ํ๋กํผํฐ์ ํด๋์ค ์ด๋ฆ์ ์ ๊ณตํฉ๋๋ค.
<ViewTransition enter="slide-in"><ViewTransition>์ด โenterโ ์ ๋๋ฉ์ด์
์ ํ์ฑํํ๋ฉด React๋ ํด๋์ค ์ด๋ฆ slide-in์ ์ถ๊ฐํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ View Transition ๊ฐ์ ์ ํ์๋ฅผ ์ฌ์ฉํ์ฌ ์ด ํด๋์ค๋ฅผ ์ฐธ์กฐํ์ฌ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ ๋๋ฉ์ด์
์ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
::view-transition-group(.slide-in) {
}
::view-transition-old(.slide-in) {
}
::view-transition-new(.slide-in) {
}ํฅํ CSS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ View Transition ํด๋์ค๋ฅผ ์ฌ์ฉํ ๋ด์ฅ ์ ๋๋ฉ์ด์ ์ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
์ฃผ์ ์ฌํญ
- ๊ธฐ๋ณธ์ ์ผ๋ก
setState๋ ์ฆ์ ์ ๋ฐ์ดํธ๋๋ฉฐ<ViewTransition>์ ํ์ฑํํ์ง ์์ต๋๋ค. Transition์ผ๋ก ๊ฐ์ผ ์ ๋ฐ์ดํธ๋ง ํ์ฑํ๋ฉ๋๋ค.<Suspense>](/reference/react/Suspense)๋ฅผ ์ฌ์ฉํ์ฌ Transition์ ์ ํ์ ์ผ๋ก ์ ์ฉํ๊ณ ์ฝํ ์ธ ๋ฅผ ํ ๋ฒ์ ํ์ํ ์๋ ์์ต๋๋ค. <ViewTransition>์ ์ด๋, ํฌ๊ธฐ ์กฐ์ ๋ฐ ํฌ๋ก์ค-ํ์ด๋๊ฐ ๊ฐ๋ฅํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํฉ๋๋ค. React Native๋ Motion์์ ๋ณผ ์ ์๋ ๋ ์ด์์ ์ ๋๋ฉ์ด์ ๊ณผ ๋ฌ๋ฆฌ, ๋ด๋ถ์ ๋ชจ๋ ๊ฐ๋ณ ์์๊ฐ ์์น๋ฅผ ์ ๋๋ฉ์ด์ ํ๋ ๊ฒ์ด ์๋๋๋ค. ์ด๋ ๋ชจ๋ ๊ฐ๋ณ ์์๋ฅผ ์ ๋๋ฉ์ด์ ํ๋ ๊ฒ์ ๋นํด ๋ ๋์ ์ฑ๋ฅ๊ณผ ๋ ์ฐ์์ ์ด๊ณ ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์ ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ ๋ฆฝ์ ์ผ๋ก ์์ง์ฌ์ผ ํ๋ ์์๋ค์ ์ฐ์์ฑ์ ์์ ์๋ ์์ต๋๋ค. ๋ฐ๋ผ์ ์๋์ผ๋ก ๋ ๋ง์<ViewTransition>๊ฒฝ๊ณ๋ฅผ ์ถ๊ฐํด์ผ ํ ์ ์์ต๋๋ค.- ๋ง์ ์ฌ์ฉ์๊ฐ ํ์ด์ง์ ์ ๋๋ฉ์ด์
์ ์ ํธํ์ง ์์ ์ ์์ต๋๋ค. React๋ ์ด ๊ฒฝ์ฐ์ ๋ํด ์๋์ผ๋ก ์ ๋๋ฉ์ด์
์ ๋นํ์ฑํํ์ง ์์ต๋๋ค. ์ฌ์ฉ์ ์ ํธ๋์ ๋ฐ๋ผ ์ ๋๋ฉ์ด์
์ ๋นํ์ฑํํ๊ฑฐ๋ ์ค์ด๊ธฐ ์ํด
@media (prefers-reduced-motion)๋ฏธ๋์ด ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ํฅํ CSS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ๋ฆฌ์ ์ ์ด ๊ธฐ๋ฅ์ด ๋ด์ฅ๋ ์ ์์ต๋๋ค. - ํ์ฌ
<ViewTransition>์ DOM์์๋ง ์๋ํฉ๋๋ค. React Native ๋ฐ ๊ธฐํ ํ๋ซํผ์ ๋ํ ์ง์์ ์ถ๊ฐํ๊ธฐ ์ํด ์์ ์ค์ ๋๋ค.
์ฌ์ฉ๋ฒ
enter/exit์์ ์๋ฆฌ๋จผํธ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
Enter/Exit Transition์ <ViewTransition>์ด Transition์์ ์ปดํฌ๋ํธ์ ์ํด ์ถ๊ฐ๋๊ฑฐ๋ ์ ๊ฑฐ๋ ๋ ๋ฐ์ํฉ๋๋ค.
function Child() {
return (
<ViewTransition>
<div>Hi</div>
</ViewTransition>
);
}
function Parent() {
const [show, setShow] = useState();
if (show) {
return <Child />;
}
return null;
}setShow๊ฐ ํธ์ถ๋๋ฉด show๊ฐ true๋ก ๋ฐ๋๊ณ Child ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋ฉ๋๋ค. setShow๊ฐ startTransition ๋ด๋ถ์์ ํธ์ถ๋๊ณ Child๊ฐ ๋ค๋ฅธ DOM ๋
ธ๋๋ณด๋ค ๋จผ์ ViewTransition์ ๋ ๋๋งํ๋ฉด enter ์ ๋๋ฉ์ด์
์ด ๋ฐ์ํฉ๋๋ค.
show๊ฐ ๋ค์ false๋ก ๋ฐ๋๋ฉด exit ์ ๋๋ฉ์ด์
์ด ๋ฐ์ํฉ๋๋ค.
import { ViewTransition, useState, startTransition } from 'react'; import {Video} from "./Video"; import videos from "./data" function Item() { return ( <ViewTransition> <Video video={videos[0]}/> </ViewTransition> ); } export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> <button onClick={() => { startTransition(() => { setShowItem((prev) => !prev); }); }} >{showItem ? 'โ' : 'โ'}</button> {showItem ? <Item /> : null} </> ); }
๊ณต์ ์๋ฆฌ๋จผํธ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
์ผ๋ฐ์ ์ผ๋ก <ViewTransition>์ ์ด๋ฆ์ ํ ๋นํ๋ ๊ฒ๋ณด๋ค React๊ฐ ์๋์ผ๋ก ์ด๋ฆ์ ํ ๋นํ๋๋ก ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ์ด๋ฆ์ ํ ๋นํ๊ณ ์ถ์ ๊ฒฝ์ฐ๋ ํ๋์ ํธ๋ฆฌ๊ฐ ๋ง์ดํธ ํด์ ๋๊ณ ๋ค๋ฅธ ํธ๋ฆฌ๊ฐ ๋์์ ๋ง์ดํธ๋ ๋ ์์ ํ ๋ค๋ฅธ ์ปดํฌ๋ํธ ๊ฐ์ ์ ๋๋ฉ์ด์
์ ์ ์ฉํ์ฌ ์ฐ์์ฑ์ ๋ณด์กดํ๊ณ ์ ํ ๋์
๋๋ค.
<ViewTransition name={UNIQUE_NAME}>
<Child />
</ViewTransition>ํ๋์ ํธ๋ฆฌ๊ฐ ๋ง์ดํธ ํด์ ๋๊ณ ๋ค๋ฅธ ํธ๋ฆฌ๊ฐ ๋ง์ดํธ๋ ๋ ๋ง์ดํธ ํด์ ๋๋ ํธ๋ฆฌ์ ๋ง์ดํธ๋๋ ํธ๋ฆฌ์์ ๋์ผํ ์ด๋ฆ์ด ์กด์ฌํ๋ ์์ด ์์ผ๋ฉด ๋ ๋ค์์ โshareโ ์ ๋๋ฉ์ด์ ์ด ๋ฐ์ํฉ๋๋ค. ๋ง์ดํธ ํด์ ๋๋ ์ชฝ์์ ๋ง์ดํธ๋๋ ์ชฝ์ผ๋ก ์ ๋๋ฉ์ด์ ์ด ์ ์ฉ๋ฉ๋๋ค.
exit/enter ์ ๋๋ฉ์ด์
๊ณผ ๋ฌ๋ฆฌ ์ญ์ ๋๊ฑฐ๋ ์๋ก ๋ง์ดํธ๋ ํธ๋ฆฌ์ ๊น์ํ ๊ณณ์์๋ ์ ์ฉ๋ ์ ์์ต๋๋ค. <ViewTransition>์ด exit/enter์๋ ํด๋นํ๋ค๋ฉด โshareโ ์ ๋๋ฉ์ด์
์ด ์ฐ์ ์์๋ฅผ ๊ฐ์ต๋๋ค.
Transition์ด ๋จผ์ ํ์ชฝ์ ๋ง์ดํธ ํด์ ํ๊ณ ์๋ก์ด ์ด๋ฆ์ด ๋ง์ดํธ๋๊ธฐ ์ ์ <Suspense> ํด๋ฐฑ์ด ํ์๋๋ ๊ฒฝ์ฐ ๊ณต์ ์๋ฆฌ๋จผํธ Transition์ ๋ฐ์ํ์ง ์์ต๋๋ค.
import { ViewTransition, useState, startTransition } from "react"; import {Video, Thumbnail, FullscreenVideo} from "./Video"; import videos from "./data"; export default function Component() { const [fullscreen, setFullscreen] = useState(false); if (fullscreen) { return <FullscreenVideo video={videos[0]} onExit={() => startTransition(() => setFullscreen(false))} /> } return <Video video={videos[0]} onClick={() => startTransition(() => setFullscreen(true))} /> }
๋ชฉ๋ก์์ ํญ๋ชฉ ์์ ๋ณ๊ฒฝ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
items.map(item => <Component key={item.id} item={item} />)์ฝํ
์ธ ๋ฅผ ์
๋ฐ์ดํธํ์ง ์๊ณ ๋ชฉ๋ก ์์๋ฅผ ๋ณ๊ฒฝํ ๋ DOM ๋
ธ๋ ๋ฐ์ ์์ผ๋ฉด ๋ชฉ๋ก์ ๊ฐ <ViewTransition>์์ โupdateโ ์ ๋๋ฉ์ด์
์ด ๋ฐ์ํฉ๋๋ค. enter/exit ์ ๋๋ฉ์ด์
๊ณผ ์ ์ฌํฉ๋๋ค.
์ด๋ ์ด <ViewTransition>์์ ์ ๋๋ฉ์ด์
์ด ๋ฐ์ํ๋ค๋ ์๋ฏธ์
๋๋ค.
function Component() {
return <ViewTransition><div>...</div></ViewTransition>;
}import { ViewTransition, useState, startTransition } from "react"; import {Video} from "./Video"; import videos from "./data"; export default function Component() { const [orderedVideos, setOrderedVideos] = useState(videos); const reorder = () => { startTransition(() => { setOrderedVideos((prev) => { return [...prev.sort(() => Math.random() - 0.5)]; }); }); }; return ( <> <button onClick={reorder}>๐ฒ</button> <div className="listContainer"> {orderedVideos.map((video, i) => { return ( <ViewTransition key={video.title}> <Video video={video} /> </ViewTransition> ); })} </div> </> ); }
ํ์ง๋ง ๋ค์์ ๊ฐ ๊ฐ๋ณ ํญ๋ชฉ์ ์ ๋๋ฉ์ด์ ์ ์ ์ฉํ์ง ์์ต๋๋ค.
function Component() {
return <div><ViewTransition>...</ViewTransition></div>;
}๋์ ๋ถ๋ชจ <ViewTransition>์ด ํฌ๋ก์ค ํ์ด๋๋ฉ๋๋ค. ๋ถ๋ชจ <ViewTransition>์ด ์์ผ๋ฉด ๋ณ๋์ ์ ๋๋ฉ์ด์
์ด ์ ์ฉ๋์ง ์์ต๋๋ค.
import { ViewTransition, useState, startTransition } from "react"; import {Video} from "./Video"; import videos from "./data"; export default function Component() { const [orderedVideos, setOrderedVideos] = useState(videos); const reorder = () => { startTransition(() => { setOrderedVideos((prev) => { return [...prev.sort(() => Math.random() - 0.5)]; }); }); }; return ( <> <button onClick={reorder}>๐ฒ</button> <ViewTransition> <div className="listContainer"> {orderedVideos.map((video, i) => { return <Video video={video} key={video.title} />; })} </div> </ViewTransition> </> ); }
์ด๋ ์ปดํฌ๋ํธ๊ฐ ์์ฒด์ ์ผ๋ก ์์ ๋ณ๊ฒฝ ์ ๋๋ฉ์ด์ ์ ์ ์ดํ ์ ์๋๋ก ํ๊ณ ์ถ์ ๋๋ ๋ฆฌ์คํธ ์์ ๋ํผ ์์๋ฅผ ๋์ง ์๋ ๊ฒ์ด ์ข๋ค๋ ๋ป์ ๋๋ค.
items.map(item => <div><Component key={item.id} item={item} /></div>)์ ๊ท์น์ ํญ๋ชฉ ์ค ํ๋๊ฐ ํฌ๊ธฐ ์กฐ์ ์ ์ํด ์
๋ฐ์ดํธ๋์ด ํ์ ํญ๋ชฉ๋ค์ด ํฌ๊ธฐ ์กฐ์ ๋๋ ๊ฒฝ์ฐ์๋ ์ ์ฉ๋๋ฉฐ, ์ด๋ ํ์ <ViewTransition>๋ ์ ๋๋ฉ์ด์
์ํค์ง๋ง ์ง์ ์ ์ธ ํ์ ์ธ ๊ฒฝ์ฐ์๋ง ํด๋นํฉ๋๋ค.
์ด๊ฒ์ ์
๋ฐ์ดํธ๊ฐ ๋ฐ์ํ์ฌ ๋ ์ด์์์ด ํฌ๊ฒ ๋ณ๊ฒฝ๋ ๋, ํ์ด์ง์ ์๋ ๋ชจ๋ <ViewTransition>์ ๊ฐ๊ฐ ๊ฐ๋ณ์ ์ผ๋ก ์ ๋๋ฉ์ด์
ํ์ง ์๋๋ค๋ ๋ป์
๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด ์ค์ ๋ณํ์ ๊ด๊ณ์๋ ๋ง์ ์ฐ๋งํ ์ ๋๋ฉ์ด์
์ด ๋ฐ์ํด ์ฃผ์๋ฅผ ํํธ๋ฌ๋จ๋ฆฌ๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ React๋ ๊ฐ๋ณ ์ ๋๋ฉ์ด์
์ ์ธ์ ํธ๋ฆฌ๊ฑฐํ ์ง์ ๋ํด ๋ณด๋ค ๋ณด์์ ์ผ๋ก ๋์ํฉ๋๋ค.
Suspense ์ฝํ ์ธ ์์ ์ ๋๋ฉ์ด์ ์ ์ฉํ๊ธฐ
๋ค๋ฅธ Transition๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก React๋ ์ ๋๋ฉ์ด์
์ ์คํํ๊ธฐ ์ ์ ๋ฐ์ดํฐ์ ์๋ก์ด CSS(<link rel="stylesheet" precedence="...">)๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด์ ๋ํด ViewTransition์ ์๋ก์ด ํฐํธ๊ฐ ๋์ค์ ๊น๋นก์ด๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ ๋๋ฉ์ด์
์ ์์ํ๊ธฐ ์ ์ ์๋ก์ด ํฐํธ๊ฐ ๋ก๋๋ ๋๊น์ง ์ต๋ 500ms๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ๊ฐ์ ์ด์ ๋ก ViewTransition์ผ๋ก ๋ํ๋ ์ด๋ฏธ์ง๋ ์ด๋ฏธ์ง๊ฐ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
์๋ก์ด Suspense ๊ฒฝ๊ณ ์ธ์คํด์ค ๋ด๋ถ์ ์์ผ๋ฉด ํด๋ฐฑ์ด ๋จผ์ ํ์๋ฉ๋๋ค. Suspense ๊ฒฝ๊ณ๊ฐ ์์ ํ ๋ก๋๋ ํ <ViewTransition>์ด ์ฝํ
์ธ ๋ก ์ ํ๋๋ ์ ๋๋ฉ์ด์
์ ์คํํฉ๋๋ค.
ํ์ฌ ์ด ๋์์ ํด๋ผ์ด์ธํธ ์ธก Transition์์๋ง ๋ฐ์ํฉ๋๋ค. ํฅํ์๋ ์ด๊ธฐ ๋ก๋ ์ค์ ์๋ฒ์ ์ฝํ ์ธ ๊ฐ ์ผ์ ์ค๋จ๋ ๋ ์คํธ๋ฆฌ๋ฐ SSR์ ๋ํ Suspense ๊ฒฝ๊ณ๋ ์ ๋๋ฉ์ด์ ํ ์์ ์ ๋๋ค.
<ViewTransition>์ ๋ฐฐ์นํ๋ ์์น์ ๋ฐ๋ผ Suspense ๊ฒฝ๊ณ๋ฅผ ์ ๋๋ฉ์ด์
ํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
Update:
<ViewTransition>
<Suspense fallback={<A />}>
<B />
</Suspense>
</ViewTransition>์ด ์๋๋ฆฌ์ค์์ ์ฝํ ์ธ ๊ฐ A์์ B๋ก ๋ฐ๋ ๋ โupdateโ๋ก ์ฒ๋ฆฌ๋๋ฉฐ ์ ์ ํ ๊ฒฝ์ฐ ํด๋น ํด๋์ค๋ฅผ ์ ์ฉํฉ๋๋ค. A์ B ๋ชจ๋ ๋์ผํ view-transition-name์ ๊ฐ๊ฒ ๋๋ฏ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก ํฌ๋ก์ค ํ์ด๋๋ก ์๋ํฉ๋๋ค.
import { ViewTransition, useState, startTransition, Suspense } from 'react'; import {Video, VideoPlaceholder} from "./Video"; import {useLazyVideoData} from "./data" function LazyVideo() { const video = useLazyVideoData(); return ( <Video video={video}/> ); } export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> <button onClick={() => { startTransition(() => { setShowItem((prev) => !prev); }); }} >{showItem ? 'โ' : 'โ'}</button> {showItem ? ( <ViewTransition> <Suspense fallback={<VideoPlaceholder />}> <LazyVideo /> </Suspense> </ViewTransition> ) : null} </> ); }
Enter/Exit:
<Suspense fallback={<ViewTransition><A /></ViewTransition>}>
<ViewTransition><B /></ViewTransition>
</Suspense>์ด ์๋๋ฆฌ์ค์์๋ ๊ฐ๊ฐ ๊ณ ์ ํ view-transition-name์ ๊ฐ๋ ๋ ๊ฐ์ ๋ณ๋ ViewTransition ์ธ์คํด์ค์
๋๋ค. ์ด๋ <A>์ โexitโ์ <B>์ โenterโ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
<ViewTransition> ๊ฒฝ๊ณ๋ฅผ ๋ฐฐ์นํ๋ ์์น์ ๋ฐ๋ผ ๋ค๋ฅธ ํจ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
์ ๋๋ฉ์ด์ ์ ์ธํ๊ธฐ
๋๋ก๋ ์ ์ฒด ํ์ด์ง์ ๊ฐ์ ํฐ ๊ธฐ์กด ์ปดํฌ๋ํธ๋ฅผ ๋ํํ๊ณ ํ ๋ง ๋ณ๊ฒฝ๊ณผ ๊ฐ์ ์ผ๋ถ ์ ๋ฐ์ดํธ๋ฅผ ์ ๋๋ฉ์ด์ ํ๊ณ ์ถ์ง๋ง ์ ์ฒด ํ์ด์ง ๋ด๋ถ์ ๋ชจ๋ ์ ๋ฐ์ดํธ๊ฐ ์ ๋ฐ์ดํธ๋ ๋ ํฌ๋ก์ค ํ์ด๋์ ํฌํจ๋๋ ๊ฒ์ ์ํ์ง ์์ ์ ์์ต๋๋ค. ํนํ ์ ์ง์ ์ผ๋ก ๋ ๋ง์ ์ ๋๋ฉ์ด์ ์ ์ถ๊ฐํ๋ ๊ฒฝ์ฐ์ ๊ทธ๋ ์ต๋๋ค.
ํด๋์ค โnoneโ์ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์ ์ ์ ์ธํ ์ ์์ต๋๋ค. ์์์ โnoneโ์ผ๋ก ๋ํํ๋ฉด ๋ถ๋ชจ๊ฐ ์ฌ์ ํ ๋ฐ์ํ๋ ๋์ ์์์ ๋ํ ์ ๋ฐ์ดํธ ์ ๋๋ฉ์ด์ ์ ๋นํ์ฑํํ ์ ์์ต๋๋ค.
<ViewTransition>
<div className={theme}>
<ViewTransition update="none">
{children}
</ViewTransition>
</div>
</ViewTransition>์ด๋ ํ
๋ง๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ์ ๋๋ฉ์ด์
๋๋ฉฐ ์์๋ง ์
๋ฐ์ดํธ๋ ๋๋ ์ ๋๋ฉ์ด์
๋์ง ์์ต๋๋ค. ์์์ ์ฌ์ ํ ์์ฒด <ViewTransition>์ผ๋ก ๋ค์ ์ฐธ์ฌํ ์ ์์ง๋ง ์ต์ํ ๋ค์ ์๋์ผ๋ก ์ ์ดํ๋ ๋ฐฉ์์ด ๋ฉ๋๋ค.
์ ๋๋ฉ์ด์ ์ปค์คํฐ๋ง์ด์ง
๊ธฐ๋ณธ์ ์ผ๋ก <ViewTransition>์ ๋ธ๋ผ์ฐ์ ์ ๊ธฐ๋ณธ ํฌ๋ก์ค ํ์ด๋๋ฅผ ํฌํจํฉ๋๋ค.
์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์งํ๋ ค๋ฉด <ViewTransition> ์ปดํฌ๋ํธ์ props๋ฅผ ์ ๊ณตํ์ฌ <ViewTransition>์ด ํ์ฑํ๋๋ ๋ฐฉ์์ ๋ฐ๋ผ ์ฌ์ฉํ ์ ๋๋ฉ์ด์
์ ์ง์ ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ๊ธฐ๋ณธ ํฌ๋ก์ค ํ์ด๋ ์ ๋๋ฉ์ด์ ์ ๋๋ฆฌ๊ฒ ํ ์ ์์ต๋๋ค.
<ViewTransition default="slow-fade">
<Video />
</ViewTransition>๊ทธ๋ฆฌ๊ณ View Transition ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ CSS์์ slow-fade๋ฅผ ์ ์ํฉ๋๋ค.
::view-transition-old(.slow-fade) {
animation-duration: 500ms;
}
::view-transition-new(.slow-fade) {
animation-duration: 500ms;
}import { ViewTransition, useState, startTransition } from 'react'; import {Video} from "./Video"; import videos from "./data" function Item() { return ( <ViewTransition default="slow-fade"> <Video video={videos[0]}/> </ViewTransition> ); } export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> <button onClick={() => { startTransition(() => { setShowItem((prev) => !prev); }); }} >{showItem ? 'โ' : 'โ'}</button> {showItem ? <Item /> : null} </> ); }
default ์ค์ ์ธ์๋ enter, exit, update, share ์ ๋๋ฉ์ด์
์ ๋ํ ๊ตฌ์ฑ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
import { ViewTransition, useState, startTransition } from 'react'; import {Video} from "./Video"; import videos from "./data" function Item() { return ( <ViewTransition enter="slide-in" exit="slide-out"> <Video video={videos[0]}/> </ViewTransition> ); } export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> <button onClick={() => { startTransition(() => { setShowItem((prev) => !prev); }); }} >{showItem ? 'โ' : 'โ'}</button> {showItem ? <Item /> : null} </> ); }
ํ์ ์ผ๋ก ์ ๋๋ฉ์ด์ ์ปค์คํฐ๋ง์ด์งํ๊ธฐ
ํน์ ํ์ฑํ ํธ๋ฆฌ๊ฑฐ์ ๋ํด ํน์ Transition ํ์
์ด ํ์ฑํ๋ ๋ ์์ ์๋ฆฌ๋จผํธ์ ํด๋์ค ์ด๋ฆ์ ์ถ๊ฐํ๊ธฐ ์ํด addTransitionType API๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๊ฐ Transition ํ์
์ ๋ํ ์ ๋๋ฉ์ด์
์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ๋ชจ๋ ์์ผ๋ก ๋ฐ ๋ค๋ก ๋ค๋น๊ฒ์ด์ ์ ๋ํ ์ ๋๋ฉ์ด์ ์ ์ปค์คํฐ๋ง์ด์งํ๋ ค๋ฉด,
<ViewTransition default={{
'navigation-back': 'slide-right',
'navigation-forward': 'slide-left',
}}>
<div>...</div>
</ViewTransition>
// ๋ผ์ฐํฐ์์:
startTransition(() => {
addTransitionType('navigation-' + navigationType);
});ViewTransition์ด โnavigation-backโ ์ ๋๋ฉ์ด์ ์ ํ์ฑํํ๋ฉด React๋ โslide-rightโ ํด๋์ค ์ด๋ฆ์ ์ถ๊ฐํฉ๋๋ค. ViewTransition์ด โnavigation-forwardโ ์ ๋๋ฉ์ด์ ์ ํ์ฑํํ๋ฉด React๋ โslide-leftโ ํด๋์ค ์ด๋ฆ์ ์ถ๊ฐํฉ๋๋ค.
ํฅํ ๋ผ์ฐํฐ์ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด ํ์ค view-transition ํ์ ๊ณผ ์คํ์ผ์ ๋ํ ์ง์์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
import { ViewTransition, addTransitionType, useState, startTransition, } from "react"; import {Video} from "./Video"; import videos from "./data" function Item() { return ( <ViewTransition enter={ { "add-video-back": "slide-in-back", "add-video-forward": "slide-in-forward" } } exit={ { "remove-video-back": "slide-in-forward", "remove-video-forward": "slide-in-back" } }> <Video video={videos[0]}/> </ViewTransition> ); } export default function Component() { const [showItem, setShowItem] = useState(false); return ( <> <div className="button-container"> <button onClick={() => { startTransition(() => { if (showItem) { addTransitionType("remove-video-back") } else { addTransitionType("add-video-back") } setShowItem((prev) => !prev); }); }} >โฌ ๏ธ</button> <button onClick={() => { startTransition(() => { if (showItem) { addTransitionType("remove-video-forward") } else { addTransitionType("add-video-forward") } setShowItem((prev) => !prev); }); }} >โก๏ธ</button> </div> {showItem ? <Item /> : null} </> ); }
View Transition ์ง์ ๋ผ์ฐํฐ ๊ตฌ์ถํ๊ธฐ
์คํฌ๋กค ๋ณต์์ด ์ ๋๋ฉ์ด์
์ค์ ์ ์์ ์ผ๋ก ๋์ํ๋๋ก, React๋ ๋๊ธฐ ์ค์ธ ๋ด๋น๊ฒ์ด์
์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ค๋น๊ฒ์ด์
์ด React์์ ์ฐจ๋จ๋๋ ๊ฒฝ์ฐ useEffect๋ ๊ต์ฐฉ ์ํ๋ก ์ด์ด์ง ์ ์์ผ๋ฏ๋ก ๋ผ์ฐํฐ๋ useLayoutEffect์์ ์ฐจ๋จ์ ํด์ ํด์ผ ํฉ๋๋ค.
โ๋ค๋กโ ๋ค๋น๊ฒ์ด์
์ค์ฒ๋ผ ๋ ๊ฑฐ์ popstate ์ด๋ฒคํธ์์ startTransition์ด ์์๋๋ฉด ์คํฌ๋กค๊ณผ ํผ ๋ณต์์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋๋ก ๋๊ธฐ์ ์ผ๋ก ์๋ฃ๋์ด์ผ ํฉ๋๋ค. ์ด๋ View Transition ์ ๋๋ฉ์ด์
์คํ๊ณผ ์ถฉ๋ํฉ๋๋ค. ๋ฐ๋ผ์ React๋ popstate์์ ์ ๋๋ฉ์ด์
์ ๊ฑด๋๋๋๋ค. ๋ฐ๋ผ์ ๋ค๋ก ๋ฒํผ์ ๋ํด์๋ ์ ๋๋ฉ์ด์
์ด ์คํ๋์ง ์์ต๋๋ค. Navigation API๋ฅผ ์ฌ์ฉํ๋๋ก ๋ผ์ฐํฐ๋ฅผ ์
๊ทธ๋ ์ด๋ํ์ฌ ์ด๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
๋ฌธ์ ํด๊ฒฐ
<ViewTransition>์ด ํ์ฑํ๋์ง ์์ต๋๋ค
<ViewTransition> only activates if it is placed before any DOM node:
function Component() {
return (
<div>
<ViewTransition>Hi</ViewTransition>
</div>
);
}ํด๊ฒฐํ๋ ค๋ฉด <ViewTransition>์ด ๋ค๋ฅธ DOM ๋
ธ๋๋ณด๋ค ์์ ์ค๋๋ก ํ์ธ์.
function Component() {
return (
<ViewTransition>
<div>Hi</div>
</ViewTransition>
);
}โ๋์ผํ ์ด๋ฆ์ผ๋ก ๋ง์ดํธ๋ <ViewTransition name=%s> ์ปดํฌ๋ํธ๊ฐ ๋ ๊ฐ ์์ต๋๋ค.โ๋ผ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค
์ด ์ค๋ฅ๋ ๋์ผํ name์ ๊ฐ์ง ๋ ๊ฐ์ <ViewTransition> ์ปดํฌ๋ํธ๊ฐ ๋์์ ๋ง์ดํธ๋ ๋ ๋ฐ์ํฉ๋๋ค.
function Item() {
// ๐ฉ ๋ชจ๋ ํญ๋ชฉ์ด ๋์ผํ "name"์ ๊ฐ๊ฒ ๋ฉ๋๋ค.
return <ViewTransition name="item">...</ViewTransition>;
}
function ItemList({items}) {
return (
<>
{item.map(item => <Item key={item.id} />)}
</>
);
}์ด๋ View Transition์์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค. ๊ฐ๋ฐ ์ค์ React๋ ์ด ๋ฌธ์ ๋ฅผ ๊ฐ์งํ์ฌ ํ๋ฉดํํ๊ณ ๋ ๊ฐ์ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
<ViewTransition name=%s> components with the same name mounted at the same time. This is not supported and will cause View Transitions to error. Try to use a more unique name e.g. by using a namespace prefix and adding the id of an item to the name.
at Item
at ItemList<ViewTransition name=%s> duplicate has this stack trace.
at Item
at ItemListํด๊ฒฐํ๋ ค๋ฉด name์ด ๊ณ ์ ํ๋๋ก ํ๊ฑฐ๋ ์ด๋ฆ์ id๋ฅผ ์ถ๊ฐํ์ฌ ์ ์ฒด ์ฑ์์ ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง <ViewTransition>์ด ํ ๋ฒ์ ํ๋๋ง ๋ง์ดํธ๋๋๋ก ํ์ธ์.
function Item({id}) {
// โ
๋ชจ๋ ํญ๋ชฉ์ด ๊ณ ์ ํ "name"์ ๊ฐ๊ฒ ๋ฉ๋๋ค.
return <ViewTransition name={`item-${id}`}>...</ViewTransition>;
}
function ItemList({items}) {
return (
<>
{item.map(item => <Item key={item.id} item={item} />)}
</>
);
}