Suspense
@suspensive/react의 <Suspense/>는 React의 Suspense 를 완전히 대체하며, 실제 프로젝트에서 필요한 추가 기능을 제공합니다.
React.Suspense 대신 사용해야 하는 이유
| React.Suspense | @suspensive/react Suspense | |
|---|---|---|
| 기본 Suspense 바운더리 | ✅ | ✅ |
SSR 안전 렌더링 (clientOnly) | ❌ | ✅ |
DefaultPropsProvider로 전역 기본 fallback | ❌ | ✅ |
HOC 패턴 (Suspense.with) | ❌ | ✅ |
Next.js 등 SSR 프레임워크에서 React의 <Suspense>는 하이드레이션 불일치를 일으킬 수 있습니다. Suspensive의 clientOnly prop은 이를 한 줄로 해결합니다 — dynamic(() => import(...), { ssr: false })나 수동 useEffect 가드가 필요 없습니다.
props.fallback
fallback은 react의 Suspense의 fallback와 동일하게 동작합니다.
import { Suspense } from '@suspensive/react'
const Example = () => (
<Suspense fallback={<Loading />}>
<Children />
</Suspense>
)Default fallback
<Suspense/>는 <DefaultPropsProvider/>와 함께 사용할 때 더욱 강력해집니다. <DefaultPropsProvider/>를 사용하여 여러 <Suspense/>의 default fallback를 제어합니다. 자세한 내용은 <DefaultPropsProvider/> 페이지에 소개되어 있습니다.
서버사이드 렌더링을 피하기 (clientOnly)
clientOnly prop을 사용하면 <Suspense/>는 서버에서는 fallback을 반환합니다. mount 후(클라이언트에서는) children을 반환합니다. mount는 클라이언트에서만 일어나기 때문에 서버사이드 렌더링을 피할 수 있습니다.
import { Suspense } from '@suspensive/react'
const Example = () => (
<Suspense clientOnly fallback={<Loading />}>
<Children />
</Suspense>
)clientOnly prop을 사용하면 내부적으로 useIsClient 훅을 사용하고 useIsClient는 useSyncExternalStore의 getSnapshot와 getServerSnapshot을 활용해 client임을 보장하고 있습니다.
const useIsClient = () =>
useSyncExternalStore(emptySubscribe, getSnapshot, getServerSnapshot)
const emptySubscribe = () => noop
const getSnapshot = () => true
const getServerSnapshot = () => falsehttps://x.com/TkDodo/status/1741068994981826947?t=XmG17etMUL2m0JFim03vqw&s=19
SSR을 지원하도록 점진적으로 마이그레이션하기 (<Suspense clientOnly/> -> <Suspense/>)
React.Suspense를 SSR과 CSR에서 모두 사용하고 싶다면 <Suspense clientOnly/>에서 <Suspense/>로 점진적으로 마이그레이션하면 쉽게 적용할 수 있습니다.
Suspense.with
Suspense.with는 Suspense를 사용하여 컴포넌트를 래핑하는 HOC입니다.
Suspense.with를 사용하면 컴포넌트를 쉽게 래핑할 수 있습니다.
import { Suspense } from '@suspensive/react'
const Example = Suspense.with({ fallback: <Spinner /> }, () => {
// code make suspending
return <>...</>
})