useTransition
useTransition
์ UI๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์ํ๋ฅผ ์
๋ฐ์ดํธํ ์ ์๋ React Hook์
๋๋ค.
const [isPending, startTransition] = useTransition()
๋ ํผ๋ฐ์ค
useTransition()
์ปดํฌ๋ํธ์ ์ต์์ ์์ค์์ useTransition
์ ํธ์ถํ์ฌ ์ผ๋ถ state ์
๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํฉ๋๋ค.
import { useTransition } from 'react';
function TabContainer() {
const [isPending, startTransition] = useTransition();
// ...
}
์๋์์ ๋ ๋ง์ ์์๋ฅผ ํ์ธํ์ธ์.
๋งค๊ฐ๋ณ์
useTransition
์ ์ด๋ค ๋งค๊ฐ๋ณ์๋ ๋ฐ์ง ์์ต๋๋ค.
๋ฐํ๊ฐ
useTransition
์ ์ ํํ ๋ ๊ฐ์ ํญ๋ชฉ์ด ์๋ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.
isPending
ํ๋๊ทธ๋ ๋๊ธฐ ์ค์ธ transition์ด ์๋์ง ์๋ ค์ค๋๋ค.startTransition
ํจ์๋ ์ํ ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํ ์ ์๊ฒ ํด์ฃผ๋ ํจ์์ ๋๋ค.
startTransition
ํจ์
useTransition
์ด ๋ฐํํ๋ startTransition
ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด state ์
๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
// ...
}
๋งค๊ฐ๋ณ์
scope
: ํ๋ ์ด์์set
ํจ์๋ฅผ ํธ์ถํ์ฌ ์ผ๋ถ state๋ฅผ ์ ๋ฐ์ดํธํ๋ ํจ์์ ๋๋ค. React๋ ๋งค๊ฐ๋ณ์ ์์ดscope
๋ฅผ ์ฆ์ ํธ์ถํ๊ณscope
ํจ์๋ฅผ ํธ์ถํ๋ ๋์ ๋๊ธฐ์ ์ผ๋ก ์์ฝ๋ ๋ชจ๋ state ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํฉ๋๋ค. ์ด๋ non-blocking์ด๋ฉฐ ์์น ์๋ ๋ก๋ฉ์ ํ์ํ์ง ์์ต๋๋ค.
๋ฐํ๊ฐ
startTransition
์ ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์ต๋๋ค.
์ฃผ์ ์ฌํญ
-
useTransition
์ Hook์ด๋ฏ๋ก ์ปดํฌ๋ํธ๋ ์ปค์คํ Hook ๋ด๋ถ์์๋ง ํธ์ถํ ์ ์์ต๋๋ค. ๋ค๋ฅธ ๊ณณ(์์: ๋ฐ์ดํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์์ transition์ ์์ํด์ผ ํ๋ ๊ฒฝ์ฐ, ๋ ๋ฆฝํstartTransition
์ ํธ์ถํ์ธ์. -
ํด๋น state์
set
ํจ์์ ์ก์ธ์คํ ์ ์๋ ๊ฒฝ์ฐ์๋ง ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ๋ํํ ์ ์์ต๋๋ค. ์ผ๋ถ prop์ด๋ ์ปค์คํ Hook ๊ฐ์ ๋ํ ์๋ต์ผ๋ก transition์ ์์ํ๋ ค๋ฉดuseDeferredValue
๋ฅผ ์ฌ์ฉํด ๋ณด์ธ์. -
startTransition
์ ์ ๋ฌํ๋ ํจ์๋ ๋๊ธฐ์์ด์ด์ผ ํฉ๋๋ค. React๋ ์ด ํจ์๋ฅผ ์ฆ์ ์คํํ์ฌ ์คํํ๋ ๋์ ๋ฐ์ํ๋ ๋ชจ๋ state ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํฉ๋๋ค. ๋์ค์ ๋ ๋ง์ state ์ ๋ฐ์ดํธ๋ฅผ ์ํํ๋ ค๊ณ ํ๋ฉด(์์: timeout), transition์ผ๋ก ํ์๋์ง ์์ต๋๋ค. -
Transition์ผ๋ก ํ์๋ state ์ ๋ฐ์ดํธ๋ ๋ค๋ฅธ state ์ ๋ฐ์ดํธ์ ์ํด ์ค๋จ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, transition ๋ด์์ ์ฐจํธ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฐ์ดํธํ ๋ค์ ์ฐจํธ๊ฐ ๋ค์ ๋ ๋๋ง ๋๋ ๋์ค์ ์ ๋ ฅ์ ์์ํ๋ฉด React๋ ์ ๋ ฅ ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ ํ ์ฐจํธ ์ปดํฌ๋ํธ์์ ๋ ๋๋ง ์์ ์ ๋ค์ ์์ํฉ๋๋ค.
-
Transition ์ ๋ฐ์ดํธ๋ ํ ์คํธ ์ ๋ ฅ์ ์ ์ดํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
-
์งํ ์ค์ธ transition์ด ์ฌ๋ฌ ๊ฐ ์๋ ๊ฒฝ์ฐ, React๋ ํ์ฌ transition์ ํจ๊ป ์ผ๊ด ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ ํฅํ ๋ฆด๋ฆฌ์ฆ์์ ์ ๊ฑฐ๋ ๊ฐ๋ฅ์ฑ์ด ๋์ ์ ํ ์ฌํญ์ ๋๋ค.
์ฌ์ฉ๋ฒ
state ์ ๋ฐ์ดํธ๋ฅผ non-blocking transition์ผ๋ก ํ์
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useTransition
์ ํธ์ถํ์ฌ state ์
๋ฐ์ดํธ๋ฅผ non-blocking transitions์ผ๋ก ํ์ํ์ธ์.
import { useState, useTransition } from 'react';
function TabContainer() {
const [isPending, startTransition] = useTransition();
// ...
}
useTransition
์ ์ ํํ ๋ ๊ฐ์ ํญ๋ชฉ์ด ์๋ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.
- ๋ณด๋ฅ ์ค์ธ transition์ด ์๋์ง๋ฅผ ์๋ ค์ฃผ๋
isPending
ํ๋๊ทธ์ ๋๋ค. - state ์
๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํ ์ ์๋
startTransition
ํจ์์ ๋๋ค.
๊ทธ ํ ๋ค์๊ณผ ๊ฐ์ด state ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
// ...
}
Transition์ ์ฌ์ฉํ๋ฉด ๋๋ฆฐ ๋๋ฐ์ด์ค์์๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์ ๋ฐ์ดํธ์ ๋ฐ์์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
Transition์ ์ฌ์ฉํ๋ฉด ๋ฆฌ๋ ๋๋ง ๋์ค์๋ UI๊ฐ ๋ฐ์์ฑ์ ์ ์งํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฌ์ฉ์๊ฐ ํญ์ ํด๋ฆญํ๋ค๊ฐ ๋ง์์ด ๋ฐ๋์ด ๋ค๋ฅธ ํญ์ ํด๋ฆญํ๋ฉด ์ฒซ ๋ฒ์งธ ๋ฆฌ๋ ๋๋ง์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ํ์ ์์ด ๋ค๋ฅธ ํญ์ ํด๋ฆญํ ์ ์์ต๋๋ค.
์์ 1 of 2: Transition์์ ํ์ฌ ํญ ์
๋ฐ์ดํธ
์ด ์์์์๋ โPostsโ ํญ์ด ์ธ์์ ์ผ๋ก ๋๋ ค์ง๋๋ก ํ์ฌ ๋ ๋๋งํ๋ ๋ฐ ์ต์ 1์ด๊ฐ ๊ฑธ๋ฆฌ๋๋ก ํ์ต๋๋ค.
โpostsโ์ ํด๋ฆญํ ๋ค์ ๋ฐ๋ก โContactโ๋ฅผ ํด๋ฆญํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด โPostsโ์ ๋๋ฆฐ ๋ ๋๋ง์ด ์ค๋จ๋ฉ๋๋ค. โContactโ ํญ์ด ์ฆ์ ํ์๋ฉ๋๋ค. ์ด state ์ ๋ฐ์ดํธ๋ transition์ผ๋ก ํ์๋๋ฏ๋ก ๋๋ฆฌ๊ฒ ๋ค์ ๋ ๋๋งํด๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๊ฐ ๋ฉ์ถ์ง ์์ต๋๋ค.
import { useState, useTransition } from 'react'; import TabButton from './TabButton.js'; import AboutTab from './AboutTab.js'; import PostsTab from './PostsTab.js'; import ContactTab from './ContactTab.js'; export default function TabContainer() { const [isPending, startTransition] = useTransition(); const [tab, setTab] = useState('about'); function selectTab(nextTab) { startTransition(() => { setTab(nextTab); }); } return ( <> <TabButton isActive={tab === 'about'} onClick={() => selectTab('about')} > About </TabButton> <TabButton isActive={tab === 'posts'} onClick={() => selectTab('posts')} > Posts (slow) </TabButton> <TabButton isActive={tab === 'contact'} onClick={() => selectTab('contact')} > Contact </TabButton> <hr /> {tab === 'about' && <AboutTab />} {tab === 'posts' && <PostsTab />} {tab === 'contact' && <ContactTab />} </> ); }
Transition์์ ์์ ์ปดํฌ๋ํธ ์ ๋ฐ์ดํธ
useTransition
ํธ์ถ์์๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ state๋ฅผ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์๋์ TabButton
์ปดํฌ๋ํธ๋ onClick
๋ก์ง์ transition์ผ๋ก ๋ํํฉ๋๋ค.
export default function TabButton({ children, isActive, onClick }) {
const [isPending, startTransition] = useTransition();
if (isActive) {
return <b>{children}</b>
}
return (
<button onClick={() => {
startTransition(() => {
onClick();
});
}}>
{children}
</button>
);
}
๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ onClick
์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด์์ state๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ๋๋ฌธ์ ํด๋น state ์
๋ฐ์ดํธ๋ transition์ผ๋ก ํ์๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์์ ์์์์์ฒ๋ผ โpostsโ์ ํด๋ฆญํ ๋ค์ ๋ฐ๋ก โContactโ๋ฅผ ํด๋ฆญํ ์ ์์ต๋๋ค. ์ ํํ ํญ์ ์
๋ฐ์ดํธํ๋ ๊ฒ์ transition์ผ๋ก ํ์๋๋ฏ๋ก ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ฐจ๋จํ์ง ์์ต๋๋ค.
import { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return <b>{children}</b> } return ( <button onClick={() => { startTransition(() => { onClick(); }); }}> {children} </button> ); }
Transition ์ค์ ๋ณด๋ฅ ์ค์ธ ์๊ฐ์ state ํ์
useTransition
์ด ๋ฐํํ๋ isPending
boolean ๊ฐ์ ์ฌ์ฉํ์ฌ transition์ด ์งํ ์ค์์ ์ฌ์ฉ์์๊ฒ ํ์ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํญ ๋ฒํผ์ ํน๋ณํ โpendingโ ์๊ฐ์ ์ํ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
function TabButton({ children, isActive, onClick }) {
const [isPending, startTransition] = useTransition();
// ...
if (isPending) {
return <b className="pending">{children}</b>;
}
// ...
์ด์ ํญ ๋ฒํผ ์์ฒด๊ฐ ๋ฐ๋ก ์ ๋ฐ์ดํธ๋๋ฏ๋ก โPostsโ์ ํด๋ฆญํ๋ ๋ฐ์์ด ๋ ๋นจ๋ผ์ง ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
import { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return <b>{children}</b> } if (isPending) { return <b className="pending">{children}</b>; } return ( <button onClick={() => { startTransition(() => { onClick(); }); }}> {children} </button> ); }
์์น ์๋ ๋ก๋ฉ ํ์๊ธฐ ๋ฐฉ์ง
์ด ์์์์ PostsTab
์ปดํฌ๋ํธ๋ Suspense-enabled ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. โPostsโ ํญ์ ํด๋ฆญํ๋ฉด PostsTab
์ปดํฌ๋ํธ๊ฐ suspends ๋์ด ๊ฐ์ฅ ๊ฐ๊น์ด ๋ก๋ฉ ํด๋ฐฑ์ด ๋ํ๋ฉ๋๋ค.
import { Suspense, useState } from 'react'; import TabButton from './TabButton.js'; import AboutTab from './AboutTab.js'; import PostsTab from './PostsTab.js'; import ContactTab from './ContactTab.js'; export default function TabContainer() { const [tab, setTab] = useState('about'); return ( <Suspense fallback={<h1>๐ Loading...</h1>}> <TabButton isActive={tab === 'about'} onClick={() => setTab('about')} > About </TabButton> <TabButton isActive={tab === 'posts'} onClick={() => setTab('posts')} > Posts </TabButton> <TabButton isActive={tab === 'contact'} onClick={() => setTab('contact')} > Contact </TabButton> <hr /> {tab === 'about' && <AboutTab />} {tab === 'posts' && <PostsTab />} {tab === 'contact' && <ContactTab />} </Suspense> ); }
๋ก๋ฉ ํ์๊ธฐ๋ฅผ ํ์ํ๊ธฐ ์ํด ์ ์ฒด ํญ ์ปจํ
์ด๋๋ฅผ ์จ๊ธฐ๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ด ์ด์ํด์ง๋๋ค. TabButton
์ useTransition
์ ์ถ๊ฐํ๋ฉด ํญ ๋ฒํผ์ ๋ณด๋ฅ ์ค์ธ ์ํ๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
โPostsโ์ ํด๋ฆญํ๋ฉด ๋ ์ด์ ์ ์ฒด ํญ ์ปจํ ์ด๋๊ฐ ์คํผ๋๋ก ๋ฐ๋์ง ์์ต๋๋ค.
import { useTransition } from 'react'; export default function TabButton({ children, isActive, onClick }) { const [isPending, startTransition] = useTransition(); if (isActive) { return <b>{children}</b> } if (isPending) { return <b className="pending">{children}</b>; } return ( <button onClick={() => { startTransition(() => { onClick(); }); }}> {children} </button> ); }
Suspense์์ transition์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์ธํ ์์๋ณด์ธ์.
Suspense-enabled ๋ผ์ฐํฐ ๊ตฌ์ถ
React ํ๋ ์์ํฌ๋ ๋ผ์ฐํฐ๋ฅผ ๊ตฌ์ถํ๋ ๊ฒฝ์ฐ ํ์ด์ง ํ์์ transition์ผ๋ก ํ์ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
function Router() {
const [page, setPage] = useState('/');
const [isPending, startTransition] = useTransition();
function navigate(url) {
startTransition(() => {
setPage(url);
});
}
// ...
๋ ๊ฐ์ง ์ด์ ๋ก ์ด ๋ฐฉ๋ฒ์ ๊ถ์ฅํฉ๋๋ค.
- Transition์ ์ค๋จํ ์ ์์ผ๋ฏ๋ก ์ฌ์ฉ์๋ ๋ฆฌ๋ ๋๋ง์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ํ์ ์์ด ๋ฐ๋ก ํด๋ฆญํ ์ ์์ต๋๋ค.
- Transition์ ์์น ์๋ ๋ก๋ฉ ํ์๊ธฐ๋ฅผ ๋ฐฉ์งํ๋ฏ๋ก ์ฌ์ฉ์๊ฐ ํ์ ์ ๊ฐ์์ค๋ฌ์ด ์ด๋์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๋ค์์ ํ์์ ์ํด transition์ ์ฌ์ฉํ๋ ์์ฃผ ๊ฐ๋จํ ๋ผ์ฐํฐ ์์์ ๋๋ค.
import { Suspense, useState, useTransition } from 'react'; import IndexPage from './IndexPage.js'; import ArtistPage from './ArtistPage.js'; import Layout from './Layout.js'; export default function App() { return ( <Suspense fallback={<BigSpinner />}> <Router /> </Suspense> ); } function Router() { const [page, setPage] = useState('/'); const [isPending, startTransition] = useTransition(); function navigate(url) { startTransition(() => { setPage(url); }); } let content; if (page === '/') { content = ( <IndexPage navigate={navigate} /> ); } else if (page === '/the-beatles') { content = ( <ArtistPage artist={{ id: 'the-beatles', name: 'The Beatles', }} /> ); } return ( <Layout isPending={isPending}> {content} </Layout> ); } function BigSpinner() { return <h2>๐ Loading...</h2>; }
๋ฌธ์ ํด๊ฒฐ
Transition์์ ์ ๋ ฅ ์ ๋ฐ์ดํธ๊ฐ ์๋ํ์ง ์์ต๋๋ค
์ ๋ ฅ์ ์ ์ดํ๋ state ๋ณ์์๋ transition์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
const [text, setText] = useState('');
// ...
function handleChange(e) {
// โ ์ ์ด๋ ์
๋ ฅ state์ transition์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
startTransition(() => {
setText(e.target.value);
});
}
// ...
return <input value={text} onChange={handleChange} />;
์ด๋ transition์ด non-blocking์ด์ง๋ง, ๋ณ๊ฒฝ ์ด๋ฒคํธ์ ๋ํ ์๋ต์ผ๋ก ์ ๋ ฅ์ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ๋๊ธฐ์ ์ผ๋ก ์ด๋ฃจ์ด์ ธ์ผ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ ๋ ฅ์ ๋ํ ์๋ต์ผ๋ก transition์ ์คํํ๋ ค๋ฉด ๋ ๊ฐ์ง ์ต์ ์ด ์์ต๋๋ค.
- ๋ ๊ฐ์ ๊ฐ๋ณ state ๋ณ์๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค. ํ๋๋ ์ ๋ ฅ state(ํญ์ ๋๊ธฐ์ ์ผ๋ก ์ ๋ฐ์ดํธ๋จ) ์ฉ์ด๊ณ ๋ค๋ฅธ ํ๋๋ transition์ ์ ๋ฐ์ดํธํ state์ ๋๋ค. ์ด๋ฅผ ํตํด ๋๊ธฐ state๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ ฅ์ ์ ์ดํ๊ณ (์ ๋ ฅ๋ณด๋ค โ์ง์ฐโ๋๋) transition state ๋ณ์๋ฅผ ๋๋จธ์ง ๋ ๋๋ง ๋ก์ง์ ์ ๋ฌํ ์ ์์ต๋๋ค.
- ๋๋ state ๋ณ์๊ฐ ํ๋ ์๊ณ ์ค์ ๊ฐ๋ณด๋ค โ์ง์ฐโ๋๋
useDeferredValue
๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด non-blocking ๋ฆฌ๋ ๋๋ง์ด ์๋ก์ด ๊ฐ์ ์๋์ผ๋ก โ๋ฐ๋ผ์ก๊ธฐโ ์ํด ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
React๊ฐ state ์ ๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ์ฒ๋ฆฌํ์ง ์์ต๋๋ค
state ์
๋ฐ์ดํธ๋ฅผ transition์ผ๋ก ๋ํํ ๋๋ startTransition
ํธ์ถ ๋์ค์ ๋ฐ์ํด์ผ ํฉ๋๋ค.
startTransition(() => {
// โ
startTransition ํธ์ถ *๋์ค* state ์ค์
setPage('/about');
});
startTransition
์ ์ ๋ฌํ๋ ํจ์๋ ๋๊ธฐ์์ด์ด์ผ ํฉ๋๋ค.
์๋์ ๊ฐ์ ์ ๋ฐ์ดํธ๋ transition์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
startTransition(() => {
// โ startTransition ํธ์ถ *ํ์* state ์ค์
setTimeout(() => {
setPage('/about');
}, 1000);
});
๋์ ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ต๋๋ค.
setTimeout(() => {
startTransition(() => {
// โ
startTransition ํธ์ถ *๋์ค* state ์ค์
setPage('/about');
});
}, 1000);
๋ง์ฐฌ๊ฐ์ง๋ก ์ ๋ฐ์ดํธ๋ฅผ ์ด์ ๊ฐ์ transition์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
startTransition(async () => {
await someAsyncFunction();
// โ startTransition ํธ์ถ *ํ์* state ์ค์
setPage('/about');
});
ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ด ๋์ ๋์ํฉ๋๋ค.
await someAsyncFunction();
startTransition(() => {
// โ
startTransition ํธ์ถ *๋์ค* state ์ค์
setPage('/about');
});
์ปดํฌ๋ํธ ์ธ๋ถ์์ useTransition
์ ํธ์ถํ๊ณ ์ถ์ต๋๋ค
Hook์ด๊ธฐ ๋๋ฌธ์ ์ปดํฌ๋ํธ ์ธ๋ถ์์ useTransition
์ ํธ์ถํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ๋์ ๋
๋ฆฝํ startTransition
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ธ์. ๋์ผํ ๋ฐฉ์์ผ๋ก ์๋ํ์ง๋ง isPending
ํ์๊ธฐ๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค.
startTransition
์ ์ ๋ฌํ ํจ์๋ ์ฆ์ ์คํ๋ฉ๋๋ค
์ด ์ฝ๋๋ฅผ ์คํํ๋ฉด 1, 2, 3์ด ์ถ๋ ฅ๋ฉ๋๋ค.
console.log(1);
startTransition(() => {
console.log(2);
setPage('/about');
});
console.log(3);
1, 2, 3์ ์ถ๋ ฅํ ๊ฒ์ผ๋ก ์์๋ฉ๋๋ค. startTransition
์ ์ ๋ฌํ ํจ์๋ ์ง์ฐ๋์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ setTimeout
๊ณผ ๋ฌ๋ฆฌ ๋์ค์ ์ฝ๋ฐฑ์ ์คํํ์ง ์์ต๋๋ค. React๋ ํจ์๋ฅผ ์ฆ์ ์คํํ์ง๋ง, ํจ์๊ฐ ์คํ๋๋ ๋์ ์์ฝ๋ ๋ชจ๋ ์ํ ์
๋ฐ์ดํธ๋ ํธ๋์ง์
์ผ๋ก ํ์๋ฉ๋๋ค. ์๋์ ๊ฐ์ด ์๋ํ๋ค๊ณ ์์ํ๋ฉด ๋ฉ๋๋ค.
// React ์๋ ๋ฐฉ์์ ๊ฐ์ํ๋ ๋ฒ์
let isInsideTransition = false;
function startTransition(scope) {
isInsideTransition = true;
scope();
isInsideTransition = false;
}
function setState() {
if (isInsideTransition) {
// ... transition state ์
๋ฐ์ดํธ ์์ฝ ...
} else {
// ... ๊ธด๊ธ state ์
๋ฐ์ดํธ ์์ฝ ...
}
}