Skip to Content

Suspense

@suspensive/react’s <Suspense/> is a drop-in replacement for React’s Suspense  — with additional features that solve real-world problems.

When to use this instead of React.Suspense

React.Suspense@suspensive/react Suspense
Basic suspense boundary
SSR-safe rendering (clientOnly)
Global default fallback via DefaultPropsProvider
HOC pattern (Suspense.with)

If you’re using Next.js or any SSR framework, React’s <Suspense> can cause hydration mismatches. Suspensive’s clientOnly prop solves this in one line — no need for dynamic(() => import(...), { ssr: false }) or manual useEffect guards.


props.fallback

fallback works the same as the fallback of React’s original Suspense.

import { Suspense } from '@suspensive/react' const Example = () => ( <Suspense fallback={<Loading />}> <Children /> </Suspense> )
import { Suspense } from '@suspensive/react'
import { use } from 'react'

export const Example = () => (
  <Suspense fallback={<div style={{ padding: 20 }}>Loading...</div>}>
    <ResolveAfter2s />
  </Suspense>
)

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
let promise: Promise<string> | null = null
const fetchData = () => {
  if (!promise) {
    promise = sleep(2000).then(() => 'Data loaded!')
  }
  return promise
}

const ResolveAfter2s = () => {
  const data = use(fetchData())
  return (
    <div style={{ padding: 20, backgroundColor: 'lightgreen' }}>{data}</div>
  )
}

Default fallback

<Suspense/> are more powerful when used with <DefaultPropsProvider/>. Control multiple <Suspense/>s default fallback with <DefaultPropsProvider/>. Details are introduced in <DefaultPropsProvider/> page.

Avoid Server side rendering (clientOnly)

If you use the clientOnly prop, <Suspense/> will return fallback in server and return children in client.

import { Suspense } from '@suspensive/react' const Example = () => ( <Suspense clientOnly fallback={<Loading />}> <Children /> </Suspense> )

When using the clientOnly prop, the useIsClient hook is used internally, and useIsClient uses getSnapshot and getServerSnapshot of useSyncExternalStore to ensure that it is a client.

const useIsClient = () => useSyncExternalStore(emptySubscribe, getSnapshot, getServerSnapshot) const emptySubscribe = () => noop const getSnapshot = () => true const getServerSnapshot = () => false

https://x.com/TkDodo/status/1741068994981826947?t=XmG17etMUL2m0JFim03vqw&s=19 

Migration support SSR gradually (<Suspense clientOnly/> -> <Suspense/>)

If you want to use Suspense working in both SSR/CSR, you can change <Suspense clientOnly/> to <Suspense/> gradually.

Suspense.with

Suspense.with is a higher-order component (HOC) that allows you to wrap a component with a Suspense boundary. Suspense.with makes it easy to wrap a component.

import { Suspense } from '@suspensive/react' const Example = Suspense.with({ fallback: <Spinner /> }, () => { // code that triggers suspense return <>...</> })
Last updated on