https://react-ko.dev/reference/react/Suspense
자식이 로딩을 완료할 때까지 fallback을 표시한다
1
2
3
<Suspense fallback={<Loading/>}>
<SomeComponent/>
</Suspense>
Props
children
: 렌더링하려는 실제 UI. 렌더링 동안children
이 일시중단되면 Suspense 경계가 fallback으로 전환된다.fallback
:children
이 일시중단되는 동안 대체할 UI.fallback
또한 중단되면 가장 가까운 상위Suspense
가 활성화된다.
Caveats
- React는 처음 마운트 하기 전에 일시 중단된 렌더링의 state를 보존하지 않는다. 컴포넌트 로드 후 일시 중단된 렌더링을 처음부터 다시 시도하다.
- Suspense가 콘텐츠를 표시하고 있다가 다시 일시 중단되면, 그것이
startTransition
이나useDeferredValue
로 인한 것이 아닌 경우fallback
이 다시 표시된다. - React가 다시 일시 중단되어 콘텐츠를 숨겨야하는 경우, 콘텐츠 트리에서
useLayoutEffect
를 클린업한다. 이후 다시 표시할 준비가 되면useLayoutEffect
를 다시 실행함으로써 콘텐츠가 숨겨져있는 동안 DOM 레이아웃을 측정하는 Effect가 해당 작업을 시도하지 않도록 한다. - React에는 Suspense와 통합된 스트리밍 서버 렌더링 및 선택적 Hydration과 같은 최적화가 포함되어 있다.
Suspense 발동 조건
오직 Suspense를 도입한 데이터 소스에서만 Suspense 를 활성화할 수 있다.
- Relay 및 next.js와 같은 Suspense 도입 프레임워크를 사용한 데이터 패칭
- lazy를 사용한 지연 로딩 컴포넌트 코드
- use를 사용해서 Promise 값 읽기
Effect나 이벤트 핸들러 내부에서 데이터 패칭을 하는 경우는 감지하지 않는다. 프레임워크를 제외한 Suspense의 사용은 현재로썬 지원되지 않는다.
Usage
Revealing content together at once
Suspense 아래 컴포넌트는 그 중 하나만 일시 중단되어도 전체가 fallback으로 대체된다.
1
2
3
4
5
6
<Suspense fallback={<Loading />}>
<Biography artistId={artist.id} />
<Panel>
<Albums artistId={artist.id} />
</Panel>
</Suspense>
Revealing nested content as it loads
컴포넌트가 일시 중단되면 가장 가까운 Suspense가 fallback을 표시한다. 이를 중첩하여 로딩 시퀀스를 만들 수 있다.
1
2
3
4
5
6
7
8
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
- Biography가 완료되면 먼저 표시하고, Album이 완료될 때까지 두번째 Suspense는 자신의 fallback을 표시한다.
Showing stale content while fresh content is loading
useDeferredValue
을 사용하여 업데이트를 연기하고 fallback 대신 이전 결과를 계속 표시할 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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=>
<SearchResults query={deferredQuery} />
</div>
</Suspense>
</>
);
}
startTransition
도 마찬가지로 할 수 있다.
Preventing already revealed content from hiding
startTransition
을 사용하여 업데이트 발생 시 이미 표시된 콘텐츠를 fallback
대신 계속 표시할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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=
/>
);
}
return (
<Layout>
{content}
</Layout>
);
}
function BigSpinner() {
return <h2>🌀 Loading...</h2>;
}