<Suspense>
는 컴포넌트 렌더링을 지연시키고 대체 UI를 보여주는 기능이다. 비동기 작업을 처리할 때 유용하게 사용할 수 있으며, 주로 데이터 로딩이나 코드 스플리팅 같은 작업에 사용된다.
로딩으로 인한 딜레이 중 사용자 경험을 개선할 수 있다. 빈 화면 대신 로딩 화면을 보여주며 사용자가 멈춤 현상을 경험하지 않게 한다.
지연을 이용해 초기에 필요한 컴포넌트만 로드하여 초기 로딩 속도를 개선할 수 있다.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
children
: 렌더링하려는 실제 UI이다. children
의 렌더링이 지연될 때, Suspense는 fallback
을 대신 렌더링한다.
fallback
: 대체 UI이다. children
의 렌더링이 지연될 때 대신 렌더링되다가, 데이터가 준비됐을 때 children
으로 다시 전환된다. 만약 fallback
의 렌더링이 지연된다면 가장 가까운 부모 Suspense가 렌더링된다.
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>;
}
위 코드는 앨범 데이터가 로딩되는 동안 Loading
컴포넌트를 표시한다. 로드가 끝났을 땐 Loading
을 숨기고 다시 Albums
컴포넌트를 렌더링한다.
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
여러 Suspense를 중첩하여 로딩 순서를 만들 수도 있다.
Biography
가 로드되지 않은 경우, BigSpinner
가 표시된다.Albums
가 로드되지 않은 경우, AlbumsGlimmer
가 표시된다.useDefferredValue
는 사용자가 빠르게 입력을 변경할 때, 결과가 즉시 업데이트되지 않고 약간 지연되도록 도와준다. 사용자 경험을 개선하고 불필요한 렌더링을 줄이는데 도움이 된다.
지연 시간은 고정되어 있지 않으며, React에 여유가 있을 때 업데이트된다. 브라우저의 현재 상태나 작업 부하에 따라 달라질 수 있다.
useDeferredValue
를 사용하면 쿼리의 지연된 버전을 아래로 전달할 수 있다.
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>
</>
);
}
위 예제는 검색 결과를 가져오는 동안 SearchResult
가 지연되며, 지연되는 동안 이전 검색 결과를 계속해서 보여준다.
예를 들어 a
를 검색하고 ab
를 검색하면, ab
의 결과를 가져오는 동안 a
의 검색 결과를 투명도 50%로 보여준다.
lazy
는 컴포넌트가 렌더링 될 때까지 로딩을 연기할 수 있다.
import { useState, Suspense, lazy } from 'react';
import Loading from './Loading.js';
const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js')));
export default function MarkdownEditor() {
const [showPreview, setShowPreview] = useState(false);
const [markdown, setMarkdown] = useState('Hello, **world**!');
return (
<>
<textarea value={markdown} onChange={e => setMarkdown(e.target.value)} />
<label>
<input type="checkbox" checked={showPreview} onChange={e => setShowPreview(e.target.checked)} />
Show preview
</label>
{showPreview && (
<Suspense fallback={<Loading />}>
<h2>Preview</h2>
<MarkdownPreview markdown={markdown} />
</Suspense>
)}
</>
);
}
위 예제는 checkbox
가 체크되기 전까지 MarkdownPreview
가 나타나지 않기 때문에, lazy
를 이용해 지연시켰다.