useTransition, uesDeferredValue
useTransition ํ ์ ์ฌ์ฉํด UI ๊ฐฑ์ ์ ์ง์ฐ์ํค๋ ๋ฐฉ๋ฒ
isPending ๋ถ๋ฆฐ ๊ฐ์ ์ฌ์ฉํด ์ผ๊ด์ฑ ์๋ ์ํ์ UI์ ๋ํ ํ๋๊ทธ๋ฅผ ๋จ๊ธฐ๋ ๋ฐฉ๋ฒ
useDefferedValue ํ ์ ์ฌ์ฉํด ์์ ๊ฐ๊ณผ ์๋ก์ด ๊ฐ์ ๋์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
SuspenseList ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด ์ฌ๋ฌ ํด๋ฐฑ UI๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ
๋์์ฑ ๋ ๋๋ง์ด ์ ๊ณตํ๋ ๊ธฐ๋ฅ ์ดํดํ๊ธฐ
Ref
๋์์ฑ ๋ชจ๋
๋์์ฑ ๋ชจ๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฆฌ์กํธ๊ฐ ๋์์ ์ฌ๋ฌ ๋ฒ์ ์ UI๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ๋ ๋๋งํ๊ณ ํ์ฌ ์ํ์ ๊ฐ์ฅ ์ ํฉํ ๋ฒ์ ๋ง DOM์ ๊ฐฑ์ ํ๋ค.
ํ์ฌ ์ํ์ ๊ฐฑ์ ์ด ์๋ฃ๋ ๋๊น์ง ์๊ฐ์ด ๊ฑธ๋ ค๋ ์ด์ ๋ฒ์ ์ UI๋ฅผ DOM์ ํ์ ๊ฐ๋ฅ
์ฐ์ ์์๊ฐ ๋ ๋์ ๊ฐฑ์ (์ฌ์ฉ์ ์ธํฐ๋ ์ )์ด ์ด๋ค์ง๋ ๋์ ๋ฆฌ์กํธ๊ฐ ๋ ๋๋ง์ ์ผ์์ค๋จ ๊ฐ๋ฅ
์ด๋ฐ ์ ์ฐ์ฑ์ ์ฑ์ ๋ฐ์์ฑ์ ์ ์งํ๊ณ ์ฌ์ฉ์๊ฐ ์ธ์งํ๋ ์ฑ์ ์ฑ๋ฅ์ ๊ฐ์ ํ๋๋ฐ ๋์์ด ๋๋ค.
๋์์ฑ ๋ ๋๋ง
๋ฆฌ์ํธ๊ฐ ํ ๋ฒ์ ์ฌ๋ฌ ๋ฒ์ ์ UI์์ ์๋ํ๊ฒ ํ๋๋ฐ, ์ ๋ฒ์ ์ด ์ค๋น๋ ๋๊น์ง ์์ ํ ์ํธ์์ฉํ ์ ์๋ ์ด์ ๋ฒ์ ์ ํ์ํ๋ค.
์ฆ, ๋จ๊ธฐ์ ์ผ๋ก ์ต์ ์ํ๊ฐ ๋ธ๋ผ์ฐ์ ์ ํ์ฌ UI์ ์ผ์นํ์ง ์์ ์๋ ์๋ค๋ ๋ป
๋์์ฑ ๋ชจ๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ฑ์ด ์ด๊ธฐ์ ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง๋๋ ๋ฐฉ์์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
// React ํ์
const root = document.getElementById('root');
ReactDOM.createRoot(root).render(<App />);
๋ชฉํ๋ ์ฑ์ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์ํ๊ณ ์ฑ์ด ๋ ๋ฐ์์ ์ผ๋ก ๋๊ปด์ง๊ฒ ๋ง๋ค๊ณ , ๊ฐฑ์ ์ ์กฐ์จํด ์ฌ์ฉ์๊ฐ ๋ฌด์์ด ์ค๋๋๊ณ ๋ฌด์์ด ๊ฐฑ์ ์ค์ด๋ฉฐ ๋ฌด์์ด ์ต์ ๋ด์ฉ์ธ์ง ์ฆ์ ์ดํดํ ์ ์๊ฒ ํ๋๊ฒ
useTransition, useDeferredValue ํ
์ปดํฌ๋ํธ๊ฐ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฌํ๊ฑฐ๋ ์ ๊ฐ์ ๊ณ์ฐํ๋ ๋์ ๋ฆฌ์กํธ๊ฐ ์ด์ UI๋ ์ด์ ๊ฐ์ ๊ณ์ ํ์ํ๋๋ก ํ์ฉ
ํํด ์ํ(receded state)๋ฅผ ๋ฐฉ์งํ๋๋ฐ ๋์์ด ๋๊ธฐ ๋๋ฌธ
๋ฆฌ์ํธ๊ฐ ์ ์ฉํ๊ณ ์ํธ์์ฉ์ด ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ฅผ ์ด์ ์ ์ ์ฌ ์ค ์ํ๋ก(์ค์๋ก) ์ ํํ๋ ๊ฒฝ์ฐ ์ด๋ฅผ ๋น์ ์์ ์ธ ์ํ๋ผ๊ณ ๋งํจ
ex: ์ฌ์ฉ์ ๋ชฉ๋ก์์ ์๋ก์ด ์ฌ์ฉ์๋ฅผ ์ ํํ๋ฉด ์ฌ์ฉ์ ์์ธ ์ ๋ณด ํจ๋์ ์คํผ๋๋ก ๋์ฒดํ๋ค. ์ด๋ ์ด์ ์ผ๋ก ๋๋์๊ฐ๋ ๋๋์ด ๋ค๊ธฐ ๋๋ฌธ์ ์ฝ๊ฐ ์ถฉ๊ฒฉ์ , ์ด๋ฐ ์ํ๋ฅผ ํํด ์ํ๋ผ ๋ถ๋ฅธ๋ค.
์์น ์๋ ๋ก๋ฉ์ ํ์ X
useTransition์ ์ฌ์ฉํด ํํด ์ํ ํผํ๊ธฐ
์คํผ๋๋ก ๋ค์ ๋์๊ฐ์ง ์๊ณ ์ด์ UI ์ ๋ณด๋ฅผ ๊ณ์ ํ์ "
startTransition
์ UI๋ฅผ Blocking ์๊ณ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๊ฒ ํด์ค๋๋ค."
์ํ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ํ์ ์ปดํฌ๋ํธ๊ฐ ์ผ์์ค๋จ๋ ๋ ๋ฆฌ์ํธ๊ฐ ์ด์ UI๋ฅผ ํ์ํ ์ ์๋๋ก useTransition ํ ์ ์ฌ์ฉ
const UserPage = () => {
const [loggedInUser] = useUser();
const [selectedUser, setSelectedUser] = useState(null);
const user = selectedUser || loggedInUser;
const queryClient = useQueryClient();
const [startTransition] = useTransition(); // startTransition ํจ์ get
const switchUser = (nextUser: User) => {
startTransition(() => setSelectedUser(nextUser)); // ์ฌ์ฉ์ ์ํ ๋ณ๊ฒฝ์ ์ ํ์ผ๋ก ๊ฐ์
// queryClient.prefetchQuery('์ฌ์ฉ์ ์์ธ ์ ๋ณด ๋ฏธ๋ฆฌ ์ฝ์ด์ค๊ธฐ');
// queryClient.prefetchQuery('์ฌ์ฉ์ ์ด๋ฏธ์ง ๋ฏธ๋ฆฌ ์ฝ์ด์ค๊ธฐ');
}
return user
? <Susepense fallback={<PageSpinner/>}>
<UserDetails userID={user.id}/>
</Suspense>
: <PageSpinner />
}
useTransition ํ ์ ํ์ ์ปดํฌ๋ํธ๊ฐ ์ผ์์ค๋จ๋ ์ ์๋ ์ํ ๋ณ๊ฒฝ์ ๊ฐ์ ๋ ์ฌ์ฉํ๋ ํจ์๊ฐ ํฌํจ๋ ๋ฐฐ์ด์ ๋ฐํ
์ ๋ฐ์ดํฐ ์ ์ฌ์ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค๋ฉด, ์ฌ์ฉ์๊ฐ ์ด์ UI๋ฅผ ๋ณด๋ฉด์ ํผ๋์ ๋น ์ง์ ์๋ค.
๋ฐ๋ผ์ ์ฑ์ด ๋ฐ์ดํฐ๋ฅผ ์ ์ฌํ๋๋ผ ๋ฐ์๋ค๋ ์ฌ์ค์ ์๋ ค์ฃผ๊ธฐ ์ํด ๋ช๊ฐ์ง ํผ๋๋ฐฑ์ ์ ๊ณตํด์ผ ํ๋ค.
const [startTransition] = useTransition();
์ํ ๋ณ๊ฒฝ ์ ์คํผ๋๋ก ๋ค์ ๋์๊ฐ์ง ์๋ ๊ฒ์ ์๋ก์ด ์ํ ๋ฐ์ดํฐ์ ์ ์ฌ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ์ง ์๋ ํ ๊ฐ์ ์ด๋ผ ํ ์ ์๋ค. (์ฆ, ์คํผ๋ ์ฐ๋ ํ์ ๊ฐ์ ์ํฉ)
isPending์ ์ฌ์ฉํด ์ฌ์ฉ์์๊ฒ ํผ๋๋ฐฑ ์ ๊ณตํ๊ธฐ
useTransition ํ ์ ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ ๋์ ๋ฆฌ์กํธ๊ฐ ์ด์ UI๋ฅผ ํ์ํ ์์๊ฒ ํด์ค๋ค. ๊ทธ๋ฌ๋, ์ผ๊ด๋์ง ์์ UI๊ฐ ์ง์๋๋ฉด ํผ๋์ ์ ๋ฐํ ์ ์๋ค. UI๊ฐ ์ค๋๋ ๊ฐ์ ๊ณ์ ํ์ํ๋๋ผ๋ ๋ณ๊ฒฝ์ด ๋ฐ์ํ๋ ์ค์์ ์ฌ์ฉ์์๊ฒ ์๋ฆฌ๋ ๋ช ๊ฐ์ง ํผ๋๋ฐฑ์ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
ex: ์ ์ฌ์ค์ธ ํจ๋์ ๋ถํฌ๋ช ๋๋ฅผ ์ค์ฌ์ ์ค๋๋์์ ๋ณด์ฌ์ฃผ๋ ๋ฑ..
์คํผ๋๋ก ํํดํ์ง ์๊ณ ํ๋ฉด์ ์ ํ์ค์์ ํ์ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋
const [isPending, startTransition] = useTransition()
์ด์ UI๋ฅผ ๊ณ์ ๋ณด์ฌ์ฃผ๋ฉด์
isPending
true๊ฐ ์ค์ ๋๊ณ ์ด์ ์ ์ผ์์ค๋จ๋ ๋ค์ ์ ๋ฐ์ดํธ UI๋ฅผ ๋ ๋๋งํ๋ค.
// ๋ฒํผ์ ๋ ๋๋งํ๋ฉด์ ์ ํ ์ฝ๋๋ ์บก์ํ
// ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ ํ์ด ์์๋๊ณ , ์ ํ์ด ์ผ์์ค๋จ ์ํ์ธ ๋์ ๋ฒํผ์ ์คํผ๋ ํ์
const ButtonPending = ({children, onClick, ...props}) => {
const [isPending, startTransition] = useTransition();
const handleClick = () => {
startTransition(onClick); // ํธ๋ค๋ฌ๋ฅผ transition์ผ๋ก ๊ฐ์
}
return (
<button onClick={handleClick} {...props}>
{isPending && <Spinner/>
{children}
{isPending && <Spinner/>
</button>
)
}
์คํผ๋๊ฐ ๋ ธ์ถ๋๋ ํ ์ด ์งง๋ค๋ฉด CSS๋ก ์๋ฐฑ๋ฐ๋ฆฌ์ด ํ์ ์คํผ๋๊ฐ ์์ํ ๋ํ๋๋๋ก ์ค์ ํด๋ด๋ผ
๋ฐ์ดํฐ๊ฐ ๋น ๋ฅด๊ฒ ์ ์ฌ๋๋ ๊ฒฝ์ฐ ์คํผ๋๋ฅผ ๋ณด์ง ๋ชปํ ๊ฒ์ด๋ค.
useDeferredValue๋ก ์ด์ ๊ฐ ์ ์งํ๊ธฐ
UI ์ผ๋ถ ์ ๋ฐ์ดํธ๋ฅผ ์ง์ฐ(deferred)์ํฌ ์ ์๋ ํ
์ง์ฐ์ ๋ฐ์์์ผ ์ ๊ฐ์ UI๋ก ๋ ๋๋งํ ์ ์์ ๋๊น์ง ์ด์ ๊ฐ์ ์ฌ์ฉ
์ฆ, ์ ๊ฐ์ ์ง์ฐ๋๋ค.
๋ฆฌ์กํธ๋ ์ด์ ๋ฒ์ (์ค๋๋ UI)๊ณผ ์ ๋ฒ์ (์ ๋ฐ์ดํธ ์ดํ UI)์ ๊ฐ์ ๋ชจ๋ ์ ์งํ๊ณ UI์์ ๋ ๋ฒ์ ์ ๋ชจ๋ ์ฌ์ฉํ๋ค.
// deferrredValue๋ undefined๋ก ์์ํ๋ฏ๋ก || user ๋์ ์ถ๊ฐํด์
// ์ด๊ธฐ user ๊ฐ์ด ์ค์ ๋์๋ง์ ๋ฐ๋ก ์ฌ์ฉํ๋๋ก ์ค์
const deferredUser = useDeferredValue(user) || user;
const isPending = deferredUser !== user;
const siwtchUser = (nextUser: User) => {
setSelectedUser(nextUser)
// queryClient.prefetchQuery('์ฌ์ฉ์ ์์ธ ์ ๋ณด ๋ฏธ๋ฆฌ ์ฝ์ด์ค๊ธฐ');
// queryClient.prefetchQuery('์ฌ์ฉ์ ์ด๋ฏธ์ง ๋ฏธ๋ฆฌ ์ฝ์ด์ค๊ธฐ');
}
return user
? <main>
<UserList
user={user} // ์ ์ฌ์ฉ์ ๋ชฉ๋ก ๋ฐ์
setUser={switchUser}
// ๋ชฉ๋ก ์ฌ์ฉ์๊ฐ details ์ฌ์ฉ์์ ์ผ์นํ์ง ์๋๋ค๋ ์ฌ์ค์ ๋ชฉ๋ก์๊ฒ ์๋ฆผ
isPending={ispending}
/>
<Susepense fallback={<PageSpinner/>}>
<UserDetails
// ์ ์ฌ์ฉ์์ ์์ธ ์ ๋ณด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ด์ ์ฌ์ฉ์์ ์์ธ์ ๋ณด ํ์
userID={deferredUser.id}
isPending={isPending} // ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์ค๋๋ ์ ๋ณด๋ผ๋ ์ฌ์ค์ ๋๊น
/>
</Suspense>
</main>
: <PageSpinner />
์ถ์ ํ ๊ฐ์ ์ธ์๋ก useDeferredValue๋ฅผ ํธ์ถ
์ด ํ ์ value๋ฅผ ์ถ์ ํด์ value๊ฐ ์ด์ ๊ฐ์์ ์ ๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ฉด ํ ์ ๋ ๊ฐ์ค ํ๋๋ฅผ ๋ฐํํ ์ ์๋ค.
๋ฆฌ์กํธ๊ฐ ์ ๊ฐ์ ์ฌ์ฉํด ์ UI๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๋ ๋๋งํ๊ณ ์์ ์ปดํฌ๋ํธ ์ค ๋ ๋๋ง์ด ์ผ์์ค๋จ๋๊ฑฐ๋ ์ง์ฐ๋ ์์์ด ์๋ค๋ฉด ํ ์ด ์ ๊ฐ์ ๋ฐํํ๊ณ , ๋ฆฌ์กํธ๋ UI๋ฅผ ๊ฐฑ์ ํ๋ค.
๋ฆฌ์กํธ๊ฐ ์ ๊ฐ์ผ๋ก ๋ ๋๋ง์ ๋ง์น๊ธฐ ์ํด ์ด๋ค ํ๋ก์ธ์ค์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ๋ ๊ฒฝ์ฐ, ํ ์ ์ด์ ๊ฐ์ ๋ฐํํ๊ณ ๋ฆฌ์กํธ๋ ๊ธฐ์กด ๊ฐ์ ์ฌ์ฉํด UI๋ฅผ ํ์ํ๋ค.(์ด์ ๋์์ ๋ฉ๋ชจ๋ฆฌ์์์ ์ ๊ฐ์ ์ฌ์ฉํด UI ์์ ์ ์ํ)
const deferredValue = useDeferredValue(value);
Last updated