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>; }
Displaying an error to users with a error boundary
If a function passed to startTransition
throws an error, you can display an error to your user with an error boundary. To use an error boundary, wrap the component where you are calling the useTransition
in an error boundary. Once the function passed to startTransition
errors, the fallback for the error boundary will be displayed.
import { useTransition } from "react"; import { ErrorBoundary } from "react-error-boundary"; export function AddCommentContainer() { return ( <ErrorBoundary fallback={<p>โ ๏ธSomething went wrong</p>}> <AddCommentButton /> </ErrorBoundary> ); } function addComment(comment) { // For demonstration purposes to show Error Boundary if(comment == null){ throw Error('Example error') } } function AddCommentButton() { const [pending, startTransition] = useTransition(); return ( <button disabled={pending} onClick={() => { startTransition(() => { // Intentionally not passing a comment // so error gets thrown addComment(); }); }}> Add comment </button> ); }
Troubleshooting
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 ์
๋ฐ์ดํธ ์์ฝ ...
}
}