React Suspense

Using React Suspense with XSWR is super natural and easy

You just have to replace all your <Loader /> with suspend()

It will suspend until the next state change, where you will choose to throw an error, suspend again, or render your component

Note: Since useEffect doesn't work when suspended, suspend() will automatically run a deduped fetch(), to avoid waiting indefinitely

Example

A traditional React component...

function Component() {
const { data, error } = useData()
if (error) return <Error />
if (!data) return <Loader />
return <div>{JSON.stringify(data)}</div>
}

...now becomes

function Component() {
const { data, error, suspend } = useData()
// Throw the error
if (error) throw error
// Fetch and suspend until next state change
if (!data) throw suspend()
return <div>{JSON.stringify(data)}</div>
}

That's it, you have control over when you suspend and when you throw ๐Ÿš€

Error handling

Throwing on error is entirely opt-in, you can also show a good old component

function Component() {
const { data, error, suspend } = useData()
// Show the error
if (error) return <>Error lol</>
// Fetch and suspend until next state change
if (!data) throw suspend()
return <div>{JSON.stringify(data)}</div>
}

If you decide to throw it, you can catch it with an Error Boundary.

Server-Side Rendering

Suspense doesn't work with SSR since the server can't use fetch. Or can it?

You can combine suspend() with useFallback

function useData(data?: Data) {
const query = useQuery(getDataSchema, [])
useFallback(query, { data })
return query
}
// Let's assume fallback will always be available on the server
function Page(props: { data?: Data }) {
const { data, suspend } = useData(props.data)
if (error) throw error
// No data means we're on the client
if (!data) throw suspend()
return ...
}

Or use any custom logic to NOT suspend on the server

function Page() {
const ssr = useAreWeOnTheServer()
const { data, suspend } = useData()
if (error) throw error
if (!data && ssr) return <>Hi server</>
if (!data && !ssr) throw suspend()
return ...
}