<Suspense>
lets you display a fallback until its children have finished loading.
<Suspense>
를 사용하면 자식이 로딩을 완료할 때까지 폴백을 표시할 수 있습니다.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
- Reference참조
- Usage사용법
- Displaying a fallback while content is loading 콘텐츠를 로딩하는 동안 폴백 표시하기
- Revealing content together at once콘텐츠를 한 번에 드러내기
- Revealing nested content as it loads중첩된 콘텐츠가 로드될 때 표시하기
- Showing stale content while fresh content is loading새 콘텐츠가 로드되는 동안 오래된 콘텐츠 표시하기
- Preventing already revealed content from hiding이미 표시된 콘텐츠가 숨겨지지 않도록 방지하기
- Indicating that a Transition is happening트랜지션이 발생하고 있음을 나타내기
- Resetting Suspense boundaries on navigation탐색시 Suspense 경계 재설정하기
- Providing a fallback for server errors and client-only content서버 오류 및 클라이언트 전용 콘텐츠에 대한 폴백 제공하기
- Troubleshooting문제 해결
Reference참조
<Suspense>
Props
-
children
: The actual UI you intend to render. Ifchildren
suspends while rendering, the Suspense boundary will switch to renderingfallback
.children
: 렌더링하려는 실제 UI입니다. 렌더링하는 동안children
이 일시 중단되면 Suspense 경계가fallback
렌더링으로 전환됩니다. -
fallback
: An alternate UI to render in place of the actual UI if it has not finished loading. Any valid React node is accepted, though in practice, a fallback is a lightweight placeholder view, such as a loading spinner or skeleton. Suspense will automatically switch tofallback
whenchildren
suspends, and back tochildren
when the data is ready. Iffallback
suspends while rendering, it will activate the closest parent Suspense boundary.fallback
: 로딩이 완료되지 않은 경우에 실제 UI 대신 렌더링할 대체 UI입니다. 유효한 어떤 React 노드든 괜찮지만 주로 로딩 스피너나 스켈레톤과 같은 가벼운 플레이스홀더 뷰를 사용합니다. Suspense는children
이 일시 중단되면 자동으로fallback
으로 전환되고, 데이터가 준비되면 다시children
으로 전환됩니다. 렌더링 중에fallback
이 일시 중단되면 가장 가까운 상위 Suspense 경계가 활성화됩니다.
Caveats주의사항
-
React does not preserve any state for renders that got suspended before they were able to mount for the first time. When the component has loaded, React will retry rendering the suspended tree from scratch. React는 처음 마운트하기 전에 일시 중단된 렌더링의 state를 보존하지 않습니다. 컴포넌트가 로드되면 React는 일시 중단된 트리의 렌더링을 처음부터 다시 시도합니다.
-
If Suspense was displaying content for the tree, but then it suspended again, the
fallback
will be shown again unless the update causing it was caused bystartTransition
oruseDeferredValue
. Suspense가 트리에 대한 콘텐츠를 표시하고 있다가 다시 일시 중단된 경우, 그 원인이 된 업데이트가startTransition
이나useDeferredValue
로 인한 것이 아니라면fallback
이 다시 표시됩니다. -
If React needs to hide the already visible content because it suspended again, it will clean up layout Effects in the content tree. When the content is ready to be shown again, React will fire the layout Effects again. This ensures that Effects measuring the DOM layout don’t try to do this while the content is hidden. React가 다시 일시 중단되어 이미 표시된 콘텐츠를 숨겨야 하는 경우, 콘텐츠 트리에서 layout Effect를 클린업 합니다. 콘텐츠가 다시 표시될 준비가 되면 React는 layout Effect를 다시 실행합니다. 이를 통해 콘텐츠가 숨겨져 있는 동안에는 DOM 레이아웃을 측정하는 Effect가 해당 작업을 시도하지 않도록 합니다.
-
React includes under-the-hood optimizations like Streaming Server Rendering and Selective Hydration that are integrated with Suspense. Read an architectural overview and watch a technical talk to learn more. React에는 Suspense와 통합된 스트리밍 서버 렌더링 및 선택적 Hydration과 같은 내부 최적화가 포함되어 있습니다. 아키텍처 개요 및 기술 강연에서 자세히 알아보세요.
Usage사용법
Displaying a fallback while content is loading 콘텐츠를 로딩하는 동안 폴백 표시하기
You can wrap any part of your application with a Suspense boundary: 애플리케이션의 어떤 부분이든 Suspense 경계로 감쌀 수 있습니다:
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
React will display your loading fallback until all the code and data needed by the children has been loaded. React는 자식에게 필요한 모든 코드와 데이터가 로드될 때까지 로딩 폴백을 표시합니다.
In the example below, the Albums
component suspends while fetching the list of albums. Until it’s ready to render, React switches the closest Suspense boundary above to show the fallback—your Loading
component. Then, when the data loads, React hides the Loading
fallback and renders the Albums
component with data.
아래 예시에서는 앨범 목록을 가져오는 동안 Albums
컴포넌트가 일시 중단됩니다. 렌더링할 준비가 될 때까지 React는 가장 가까운 상위 Suspense 경계를 폴백인 Loading
컴포넌트로 전환하여 표시합니다. 이후 데이터가 로드되면 React는 Loading
폴백을 숨기고 데이터와 함께 Albums
컴포넌트를 렌더링합니다.
import { Suspense } from 'react'; import Albums from './Albums.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<Loading />}> <Albums artistId={artist.id} /> </Suspense> </> ); } function Loading() { return <h2>🌀 Loading...</h2>; }
Revealing content together at once콘텐츠를 한 번에 드러내기
By default, the whole tree inside Suspense is treated as a single unit. For example, even if only one of these components suspends waiting for some data, all of them together will be replaced by the loading indicator: 기본적으로 Suspense 내부의 전체 트리는 단일 단위로 취급됩니다. 예를 들어, 다음 컴포넌트 중 하나만 데이터 대기를 위해 일시 중단하더라도 모든 컴포넌트가 함께 로딩 표시기로 대체됩니다:
<Suspense fallback={<Loading />}>
<Biography />
<Panel>
<Albums />
</Panel>
</Suspense>
Then, after all of them are ready to be displayed, they will all appear together at once. 이후 모든 항목이 표시될 준비가 되면, 이들 모두가 한꺼번에 표시됩니다.
In the example below, both Biography
and Albums
fetch some data. However, because they are grouped under a single Suspense boundary, these components always “pop in” together at the same time.
아래 예제에서는 Biography
와 Albums
모두 데이터를 가져옵니다. 그러나 이 두 컴포넌트는 단일 Suspense 경계 아래에 그룹화되어 있기 때문에 항상 동시에 함께 “등장”합니다.
import { Suspense } from 'react'; import Albums from './Albums.js'; import Biography from './Biography.js'; import Panel from './Panel.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<Loading />}> <Biography artistId={artist.id} /> <Panel> <Albums artistId={artist.id} /> </Panel> </Suspense> </> ); } function Loading() { return <h2>🌀 Loading...</h2>; }
Components that load data don’t have to be direct children of the Suspense boundary. For example, you can move Biography
and Albums
into a new Details
component. This doesn’t change the behavior. Biography
and Albums
share the same closest parent Suspense boundary, so their reveal is coordinated together.
데이터를 로드하는 컴포넌트가 Suspense 경계의 직접적인 자식일 필요는 없습니다. 예를 들어, Biography
와 Albums
를 새 Details
컴포넌트로 이동할 수도 있습니다. 이렇게 해도 동작은 달라지지 않습니다. Biography
와 Albums
는 가장 가까운 상위 Suspense 경계를 공유하므로 표시 여부가 함께 조정됩니다.
<Suspense fallback={<Loading />}>
<Details artistId={artist.id} />
</Suspense>
function Details({ artistId }) {
return (
<>
<Biography artistId={artistId} />
<Panel>
<Albums artistId={artistId} />
</Panel>
</>
);
}
Revealing nested content as it loads중첩된 콘텐츠가 로드될 때 표시하기
When a component suspends, the closest parent Suspense component shows the fallback. This lets you nest multiple Suspense components to create a loading sequence. Each Suspense boundary’s fallback will be filled in as the next level of content becomes available. For example, you can give the album list its own fallback: 컴포넌트가 일시 중단되면 가장 가까운 상위 Suspense 컴포넌트가 폴백을 표시합니다. 이를 통해 여러 Suspense 컴포넌트를 중첩하여 로딩 시퀀스를 만들 수 있습니다. 각 Suspense 경계의 폴백은 다음 레벨의 콘텐츠를 사용할 수 있게 되면 채워집니다. 예를 들어, 앨범 목록에 자체 폴백을 지정할 수 있습니다:
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
With this change, displaying the Biography
doesn’t need to “wait” for the Albums
to load.
이 변경으로, Biography
를 표시하기 위해 Albums
가 로드될 때까지 “기다릴” 필요가 없어졌습니다.
The sequence will be: 순서는 다음과 같습니다:
-
If
Biography
hasn’t loaded yet,BigSpinner
is shown in place of the entire content area.Biography
가 아직 로드되지 않은 경우 전체 콘텐츠 영역 대신BigSpinner
가 표시됩니다. -
Once
Biography
finishes loading,BigSpinner
is replaced by the content.Biography
로드가 완료되면BigSpinner
가 콘텐츠로 대체됩니다. -
If
Albums
hasn’t loaded yet,AlbumsGlimmer
is shown in place ofAlbums
and its parentPanel
.Albums
가 아직 로드되지 않은 경우Albums
및 그 부모Panel
대신AlbumsGlimmer
가 표시됩니다. -
Finally, once
Albums
finishes loading, it replacesAlbumsGlimmer
. 마지막으로Albums
로딩이 완료되면Albums
가AlbumsGlimmer
를 대체합니다.
import { Suspense } from 'react'; import Albums from './Albums.js'; import Biography from './Biography.js'; import Panel from './Panel.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<BigSpinner />}> <Biography artistId={artist.id} /> <Suspense fallback={<AlbumsGlimmer />}> <Panel> <Albums artistId={artist.id} /> </Panel> </Suspense> </Suspense> </> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; } function AlbumsGlimmer() { return ( <div className="glimmer-panel"> <div className="glimmer-line" /> <div className="glimmer-line" /> <div className="glimmer-line" /> </div> ); }
Suspense boundaries let you coordinate which parts of your UI should always “pop in” together at the same time, and which parts should progressively reveal more content in a sequence of loading states. You can add, move, or delete Suspense boundaries in any place in the tree without affecting the rest of your app’s behavior. Suspense 경계를 사용하면 UI의 어떤 부분이 항상 동시에 “등장”해야 하는지, 어떤 부분이 로딩 상태의 시퀀스에서 점진적으로 더 많은 콘텐츠를 표시해야 하는지 조정할 수 있습니다. 앱의 나머지 동작에 영향을 주지 않고 트리의 어느 위치에서나 Suspense 경계를 추가, 이동, 삭제할 수 있습니다.
Don’t put a Suspense boundary around every component. Suspense boundaries should not be more granular than the loading sequence that you want the user to experience. If you work with a designer, ask them where the loading states should be placed—it’s likely that they’ve already included them in their design wireframes. 모든 컴포넌트에 Suspense 경계를 설정하지 마세요. Suspense 경계는 사용자가 경험하게 될 로딩 시퀀스보다 더 세분화되어서는 안 됩니다. 디자이너와 함께 작업하는 경우 로딩 상태를 어디에 배치해야 하는지 디자이너에게 물어보세요. 디자이너가 이미 디자인 와이어프레임에 포함시켰을 가능성이 높습니다.
Showing stale content while fresh content is loading새 콘텐츠가 로드되는 동안 오래된 콘텐츠 표시하기
In this example, the SearchResults
component suspends while fetching the search results. Type "a"
, wait for the results, and then edit it to "ab"
. The results for "a"
will get replaced by the loading fallback.
아래 예제에서는 검색 결과를 가져오는 동안 SearchResults
컴포넌트가 일시 중단됩니다. "a"
를 입력하고 결과를 기다린 다음 "ab"
를 다시 입력하면 "a"
에 대한 결과는 로딩 폴백으로 대체됩니다.
import { Suspense, useState } from 'react'; import SearchResults from './SearchResults.js'; export default function App() { const [query, setQuery] = useState(''); return ( <> <label> Search albums: <input value={query} onChange={e => setQuery(e.target.value)} /> </label> <Suspense fallback={<h2>Loading...</h2>}> <SearchResults query={query} /> </Suspense> </> ); }
A common alternative UI pattern is to defer updating the list and to keep showing the previous results until the new results are ready. The useDeferredValue
Hook lets you pass a deferred version of the query down:
일반적인 대체 UI 패턴은 목록 업데이트를 연기하고 새 결과가 준비될 때까지 이전 결과를 계속 표시하는 것입니다. useDeferredValue
훅을 사용하면 쿼리의 지연된 버전을 전달할 수 있습니다:
export default function App() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
return (
<>
<label>
Search albums:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<SearchResults query={deferredQuery} />
</Suspense>
</>
);
}
The query
will update immediately, so the input will display the new value. However, the deferredQuery
will keep its previous value until the data has loaded, so SearchResults
will show the stale results for a bit.
query
가 즉시 업데이트되므로 input에 새 값이 표시됩니다. 그러나 deferredQuery
는 데이터가 로드될 때까지 이전 값을 유지하므로 SearchResults
는 잠시 동안 이전 결과를 표시합니다.
To make it more obvious to the user, you can add a visual indication when the stale result list is displayed: 사용자에게 더 명확하게 알리기 위해 이전 결과 목록이 표시될 때 시각적 표시를 추가할 수 있습니다:
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
Enter "a"
in the example below, wait for the results to load, and then edit the input to "ab"
. Notice how instead of the Suspense fallback, you now see the dimmed stale result list until the new results have loaded:
아래 예제에서 "a"
를 입력하고 결과가 로드될 때까지 기다린 다음 입력을 "ab"
로 변경해 보세요. 이제 새 결과가 로드될 때까지 일시 중단 폴백 대신 이전 결과 목록이 흐리게 표시되는 것을 확인할 수 있습니다:
import { Suspense, useState, useDeferredValue } from 'react'; import SearchResults from './SearchResults.js'; export default function App() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); const isStale = query !== deferredQuery; return ( <> <label> Search albums: <input value={query} onChange={e => setQuery(e.target.value)} /> </label> <Suspense fallback={<h2>Loading...</h2>}> <div style={{ opacity: isStale ? 0.5 : 1 }}> <SearchResults query={deferredQuery} /> </div> </Suspense> </> ); }
Preventing already revealed content from hiding이미 표시된 콘텐츠가 숨겨지지 않도록 방지하기
When a component suspends, the closest parent Suspense boundary switches to showing the fallback. This can lead to a jarring user experience if it was already displaying some content. Try pressing this button: 컴포넌트가 일시 중단되면 가장 가까운 상위 Suspense 경계가 폴백으로 전환됩니다. 이미 일부 콘텐츠가 표시되고 있는 경우 사용자 경험이 끊길 수 있습니다. 아래 예제의 버튼을 눌러 보세요:
import { Suspense, useState } 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('/'); function navigate(url) { 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> {content} </Layout> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; }
When you pressed the button, the Router
component rendered ArtistPage
instead of IndexPage
. A component inside ArtistPage
suspended, so the closest Suspense boundary started showing the fallback. The closest Suspense boundary was near the root, so the whole site layout got replaced by BigSpinner
.
버튼을 누르자 Router
컴포넌트가 IndexPage
대신 ArtistPage
를 렌더링했습니다. ArtistPage
내부의 컴포넌트가 일시 중단되었기 때문에 가장 가까운 Suspense 경계가 폴백을 표시하기 시작했습니다. 가장 가까운 Suspense 경계는 루트 근처에 있었기 때문에 전체 사이트 레이아웃이 BigSpinner
로 대체되었습니다.
To prevent this, you can mark the navigation state update as a Transition with startTransition
:
이를 방지하려면 startTransition
을 사용하여 탐색 state 업데이트를 트랜지션으로 표시할 수 있습니다:
function Router() {
const [page, setPage] = useState('/');
function navigate(url) {
startTransition(() => {
setPage(url);
});
}
// ...
This tells React that the state transition is not urgent, and it’s better to keep showing the previous page instead of hiding any already revealed content. Now clicking the button “waits” for the Biography
to load:
이 방법은 React에게 state 전환이 긴급하지 않으며 이미 표시된 콘텐츠를 숨기는 대신 이전 페이지를 계속 표시하는 것이 낫다고 알려줍니다. 이제 버튼을 클릭하면 Biography
가 로드될 때까지 “대기” 상태가 됩니다:
import { Suspense, startTransition, useState } 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('/'); 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> {content} </Layout> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; }
A Transition doesn’t wait for all content to load. It only waits long enough to avoid hiding already revealed content. For example, the website Layout
was already revealed, so it would be bad to hide it behind a loading spinner. However, the nested Suspense
boundary around Albums
is new, so the Transition doesn’t wait for it.
트랜지션은 모든 콘텐츠가 로드될 때까지 기다리지 않습니다. 오직 이미 표시된 콘텐츠가 숨겨지지 않을 만큼만 기다립니다. 예를 들어, 웹사이트 Layout
이 이미 표시된 경우 이를 다시 로딩 스피너 뒤로 숨기는 것은 좋지 않을 것입니다. 그러나 Albums
주위의 중첩된 Suspense
경계는 새로운 것이므로, 트랜지션은 이를 기다리지 않습니다.
Indicating that a Transition is happening트랜지션이 발생하고 있음을 나타내기
In the above example, once you click the button, there is no visual indication that a navigation is in progress. To add an indicator, you can replace startTransition
with useTransition
which gives you a boolean isPending
value. In the example below, it’s used to change the website header styling while a Transition is happening:
위의 예제에서는 버튼을 클릭해도 탐색이 진행 중이라는 시각적 표시가 없습니다. 표시기를 추가하려면 startTransition
을 isPending
이라는 불리언 값을 제공하는 useTransition
으로 대체하면 됩니다. 아래 예제에서는 트랜지션이 진행되는 동안 웹사이트 헤더 스타일을 변경하는 데 사용됩니다:
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>; }
Resetting Suspense boundaries on navigation탐색시 Suspense 경계 재설정하기
During a Transition, React will avoid hiding already revealed content. However, if you navigate to a route with different parameters, you might want to tell React it is different content. You can express this with a key
:
트랜지션하는 동안 React는 이미 표시된 콘텐츠를 숨기지 않습니다. 하지만 다른 매개변수가 있는 경로로 이동하는 경우 React에게 다른 콘텐츠라고 알려줄 필요가 있습니다. Key
를 사용하여 표현할 수 있습니다:
<ProfilePage key={queryParams.id} />
Imagine you’re navigating within a user’s profile page, and something suspends. If that update is wrapped in a Transition, it will not trigger the fallback for already visible content. That’s the expected behavior. 어떤 사용자의 프로필 페이지를 둘러보던 중에 무언가가 일시 중단되었다고 가정해 봅시다. 해당 업데이트가 트랜지션으로 감싸져 있으면 이미 표시된 콘텐츠에 대한 폴백이 촉발되지 않을 것입니다. 이는 예상되는 동작입니다.
However, now imagine you’re navigating between two different user profiles. In that case, it makes sense to show the fallback. For example, one user’s timeline is different content from another user’s timeline. By specifying a key
, you ensure that React treats different users’ profiles as different components, and resets the Suspense boundaries during navigation. Suspense-integrated routers should do this automatically.
이번에는 두 개의 서로 다른 사용자 프로필 사이를 탐색하고 있다고 가정해 봅시다. 이 경우에는 폴백을 표시하는 것이 좋을 것입니다. 예를 들어, 한 사용자의 타임라인은 다른 사용자의 타임라인과 다른 콘텐츠입니다. Key
를 지정하면 React가 서로 다른 사용자의 프로필을 서로 다른 컴포넌트로 취급하고 탐색 중에 Suspense 경계를 재설정하도록 할 수 있습니다. Suspense 통합 라우터는 이 작업을 자동으로 수행해야 합니다.
Providing a fallback for server errors and client-only content서버 오류 및 클라이언트 전용 콘텐츠에 대한 폴백 제공하기
If you use one of the streaming server rendering APIs (or a framework that relies on them), React will also use your <Suspense>
boundaries to handle errors on the server. If a component throws an error on the server, React will not abort the server render. Instead, it will find the closest <Suspense>
component above it and include its fallback (such as a spinner) into the generated server HTML. The user will see a spinner at first.
스트리밍 서버 렌더링 API 중 하나 (또는 이에 의존하는 프레임워크)를 사용하는 경우, React는 서버에서 발생하는 오류를 처리하기 위해 <Suspense>
바운더리도 사용합니다. 컴포넌트가 서버에서 에러를 발생시키더라도 React는 서버 렌더링을 중단하지 않습니다. 대신, 그 위에 있는 가장 가까운 <Suspense>
컴포넌트를 찾아서 생성된 서버 HTML에 그 폴백(예: 스피너)을 포함시킵니다. 사용자는 처음에 스피너를 보게 됩니다.
On the client, React will attempt to render the same component again. If it errors on the client too, React will throw the error and display the closest error boundary. However, if it does not error on the client, React will not display the error to the user since the content was eventually displayed successfully. 클라이언트에서 React는 동일한 컴포넌트를 다시 렌더링하려고 시도합니다. 클라이언트에서도 에러가 발생하면 React는 에러를 던지고 가장 가까운 에러 경계를 표시합니다. 그러나 클라이언트에서 에러가 발생하지 않는다면, 결국 콘텐츠가 성공적으로 표시되었기 때문에 React는 사용자에게 에러를 표시하지 않습니다.
You can use this to opt out some components from rendering on the server. To do this, throw an error in the server environment and then wrap them in a <Suspense>
boundary to replace their HTML with fallbacks:
이를 이용하여 일부 컴포넌트를 서버에서 렌더링하지 않도록 선택할 수 있습니다. 이렇게 하려면 서버 환경에서 오류를 발생시킨 다음 해당 컴포넌트를 <Suspense>
경계로 감싸서 해당 HTML을 폴백으로 대체하면 됩니다:
<Suspense fallback={<Loading />}>
<Chat />
</Suspense>
function Chat() {
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
The server HTML will include the loading indicator. It will be replaced by the Chat
component on the client.
서버 HTML에는 로딩 표시기가 포함됩니다. 이 표시기는 클라이언트에서는 Chat
컴포넌트로 대체됩니다.
Troubleshooting문제 해결
How do I prevent the UI from being replaced by a fallback during an update?업데이트 중에 UI가 폴백으로 대체되는 것을 방지하려면 어떻게 해야 할까요?
Replacing visible UI with a fallback creates a jarring user experience. This can happen when an update causes a component to suspend, and the nearest Suspense boundary is already showing content to the user. 표시되는 UI를 폴백으로 대체하면 사용자 환경이 불안정해집니다. 이는 업데이트로 인해 컴포넌트가 일시 중단되었는데 가장 가까운 Suspense 경계에는 이미 콘텐츠가 표시되고 있을 때 발생할 수 있습니다.
To prevent this from happening, mark the update as non-urgent using startTransition
. During a Transition, React will wait until enough data has loaded to prevent an unwanted fallback from appearing:
이런 일이 발생하지 않도록 하려면 startTransition
을 사용하여 업데이트를 긴급하지 않은 것으로 표시하세요. 트랜지션이 진행되는 동안 React는 원치 않는 폴백이 나타나지 않기에 충분한 데이터가 로드될 때까지 기다립니다:
function handleNextPageClick() {
// If this update suspends, don't hide the already displayed content
// 이 업데이트가 일시 중단되어도 이미 표시된 콘텐츠를 숨기지 않습니다
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
This will avoid hiding existing content. However, any newly rendered Suspense
boundaries will still immediately display fallbacks to avoid blocking the UI and let the user see the content as it becomes available.
이렇게 하면 기존 콘텐츠가 숨겨지지 않습니다. 반면 새로 렌더링된 Suspense
경계는 여전히 UI를 가리지 않기 위해 즉시 폴백을 표시하며, 콘텐츠는 사용할 수 있게 될 때 노출합니다.
React will only prevent unwanted fallbacks during non-urgent updates. It will not delay a render if it’s the result of an urgent update. You must opt in with an API like startTransition
or useDeferredValue
.
React는 긴급하지 않은 업데이트 중에만 원치 않는 폴백을 방지합니다. 긴급한 업데이트의 결과인 경우 렌더링을 지연시키지 않습니다. startTransition
또는 useDeferredValue
와 같은 API를 사용해야 합니다.
If your router is integrated with Suspense, it should wrap its updates into startTransition
automatically.
라우터가 Suspense와 통합되어 있는 경우, 라우터는 업데이트를 startTransition
으로 자동으로 감싸야 합니다.