Skip to content

Commit 4320796

Browse files
authored
fix: do not error when not enabled during suspense (#4156)
1 parent bb59341 commit 4320796

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use client'
2+
3+
import { Suspense, useReducer } from 'react'
4+
import useSWR from 'swr'
5+
6+
const fetcher = async (key: string) => {
7+
// Add a small delay to simulate network request
8+
await new Promise(resolve => setTimeout(resolve, 100))
9+
return 'SWR'
10+
}
11+
12+
const Section = ({ trigger }: { trigger: boolean }) => {
13+
const { data } = useSWR(trigger ? 'test-key' : undefined, fetcher, {
14+
suspense: true
15+
})
16+
return <div>{data || 'empty'}</div>
17+
}
18+
19+
export default function Page() {
20+
const [trigger, toggle] = useReducer(x => !x, false)
21+
22+
return (
23+
<div>
24+
<button onClick={toggle}>toggle</button>
25+
<Suspense fallback={<div>fallback</div>}>
26+
<Section trigger={trigger} />
27+
</Suspense>
28+
</div>
29+
)
30+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* eslint-disable testing-library/prefer-screen-queries */
2+
import { test, expect } from '@playwright/test'
3+
4+
test.describe('suspense with undefined key', () => {
5+
test('should render correctly when key is undefined', async ({ page }) => {
6+
await page.goto('./suspense-undefined-key', { waitUntil: 'commit' })
7+
8+
// Should show content for undefined key (not suspense)
9+
await expect(page.getByText('empty')).toBeVisible()
10+
11+
// Click toggle to enable key
12+
await page.getByRole('button', { name: 'toggle' }).click()
13+
14+
// Should show loading fallback when key becomes defined
15+
await expect(page.getByText('fallback')).toBeVisible()
16+
17+
// Should eventually show the fetched data
18+
await expect(page.getByText('SWR')).toBeVisible()
19+
})
20+
})

src/index/use-swr.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,14 +714,14 @@ export const useSWRHandler = <Data = any, Error = any>(
714714
// If there is no `error`, the `revalidation` promise needs to be thrown to
715715
// the suspense boundary.
716716
if (suspense) {
717+
const hasKeyButNoData = key && isUndefined(data)
717718
// SWR should throw when trying to use Suspense on the server with React 18,
718719
// without providing any fallback data. This causes hydration errors. See:
719720
// https://github.com/vercel/swr/issues/1832
720-
if (!IS_REACT_LEGACY && IS_SERVER) {
721+
if (!IS_REACT_LEGACY && IS_SERVER && hasKeyButNoData) {
721722
throw new Error('Fallback data is required when using Suspense in SSR.')
722723
}
723724

724-
const hasKeyButNoData = key && isUndefined(data)
725725
// Always update fetcher and config refs even with the Suspense mode.
726726
if (hasKeyButNoData) {
727727
fetcherRef.current = fetcher

0 commit comments

Comments
 (0)