From 6b47d0b93f7862e937621baa9fc8b2d172f5b4dc Mon Sep 17 00:00:00 2001 From: David Condrey <davidcondrey@me.com> Date: Thu, 17 Apr 2025 03:26:30 -0700 Subject: [PATCH 1/4] Update types.ts Add configuration option to skip revalidation when data comes from RSC fallback --- src/_internal/types.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/_internal/types.ts b/src/_internal/types.ts index 528dae9327..4e46049e89 100644 --- a/src/_internal/types.ts +++ b/src/_internal/types.ts @@ -116,6 +116,11 @@ export interface PublicConfiguration< * @link https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations */ revalidateIfStale: boolean + /** + * automatically revalidate when data comes from RSC fallback + * @defaultValue false + */ + revalidateOnRSCFallback?: boolean /** * retry when fetcher has an error * @defaultValue true From 284aa42b1c62196554f58bd7ed0eb45c510038e5 Mon Sep 17 00:00:00 2001 From: David Condrey <davidcondrey@me.com> Date: Thu, 17 Apr 2025 03:34:09 -0700 Subject: [PATCH 2/4] Update use-swr.ts For data coming from RSC fallback, respect revalidateOnRSCFallback option --- src/index/use-swr.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index/use-swr.ts b/src/index/use-swr.ts index 21c42a9c2e..c91cc3156b 100644 --- a/src/index/use-swr.ts +++ b/src/index/use-swr.ts @@ -299,6 +299,9 @@ export const useSWRHandler = <Data = any, Error = any>( // If it's paused, we skip revalidation. if (getConfig().isPaused()) return false + // If RSC fallback data on initial render, use revalidateOnRSCFallback config + if (!isUndefined(fallback) && !isUndefined(data) && !IS_SERVER && isInitialMount) return getConfig().revalidateOnRSCFallback ?? false; + // Under suspense mode, it will always fetch on render if there is no // stale data so no need to revalidate immediately mount it again. // If data exists, only revalidate if `revalidateIfStale` is true. From 4beefb1ba9aa263e50465eab0bf975e852e6f1d7 Mon Sep 17 00:00:00 2001 From: David Condrey <davidcondrey@me.com> Date: Thu, 17 Apr 2025 03:36:59 -0700 Subject: [PATCH 3/4] Update config.ts Add revalidateOnRSCFallback default value --- src/_internal/utils/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_internal/utils/config.ts b/src/_internal/utils/config.ts index ce05caea25..986cc6e4a1 100644 --- a/src/_internal/utils/config.ts +++ b/src/_internal/utils/config.ts @@ -60,6 +60,7 @@ export const defaultConfig: FullConfiguration = mergeObjects( revalidateOnReconnect: true, revalidateIfStale: true, shouldRetryOnError: true, + revalidateOnRSCFallback: false, // timeouts errorRetryInterval: slowConnection ? 10000 : 5000, From 8bf6aafd8396349764dea18f0a6006a2732605e9 Mon Sep 17 00:00:00 2001 From: David Condrey <davidcondrey@me.com> Date: Thu, 17 Apr 2025 03:43:26 -0700 Subject: [PATCH 4/4] Create rsc-fallback.test.tsx Create a test file to verify revalidateOnRSCFallback --- test/rsc-fallback.test.tsx | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/rsc-fallback.test.tsx diff --git a/test/rsc-fallback.test.tsx b/test/rsc-fallback.test.tsx new file mode 100644 index 0000000000..3a6564f7ca --- /dev/null +++ b/test/rsc-fallback.test.tsx @@ -0,0 +1,47 @@ +import { act, fireEvent, render, screen } from '@testing-library/react' +import React from 'react' +import useSWR, { SWRConfig } from 'swr' +import { sleep } from './utils' + +describe('RSC Fallback', () => { + it('should not revalidate on mount with RSC fallback data by default', async () => { + const fetchFn = jest.fn(() => 'updated data') + + function Page() { + const { data } = useSWR('key', fetchFn, { + fallbackData: 'RSC data' + }) + return <div>Data: {data}</div> + } + + render(<Page />) + + expect(screen.getByText('Data: RSC data')).toBeInTheDocument() + expect(fetchFn).not.toHaveBeenCalled() + + await sleep(50) + + expect(fetchFn).not.toHaveBeenCalled() + }) + + it('should revalidate on mount with RSC fallback data when revalidateOnRSCFallback is true', async () => { + const fetchFn = jest.fn(() => 'updated data') + + function Page() { + const { data } = useSWR('key', fetchFn, { + fallbackData: 'RSC data', + revalidateOnRSCFallback: true + }) + return <div>Data: {data}</div> + } + + render(<Page />) + + expect(screen.getByText('Data: RSC data')).toBeInTheDocument() + expect(fetchFn).toHaveBeenCalledTimes(1) + + await sleep(50) + + expect(screen.getByText('Data: updated data')).toBeInTheDocument() + }) +})