feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(shared): Support for keepPreviousData in useSubscription.rq - #7203

Merged
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq
Nov 13, 2025
Merged

feat(shared): Support for keepPreviousData in useSubscription.rq#7203
panteliselef merged 10 commits into
mainfrom
elef/add-support-for-keep-previous-data-in-rq

Conversation

@panteliselef

@panteliselefpanteliselef commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Added support for keepPreviousData in subscription and pagination hooks so previous results can persist during refetches.
  • Tests

    • Added tests verifying behavior when keepPreviousData is enabled (retains data) and disabled (clears data) during refetches.
  • Documentation

    • Added changelog entry describing this patch release.

@changeset-bot

changeset-botBot commented Nov 11, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 85a1cb5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
NameType
@clerk/sharedPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/chrome-extensionPatch
@clerk/clerk-jsPatch
@clerk/elementsPatch
@clerk/expo-passkeysPatch
@clerk/clerk-expoPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/clerk-reactPatch
@clerk/remixPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/themesPatch
@clerk/typesPatch
@clerk/vuePatch
@clerk/localizationsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Nov 11, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
clerk-js-sandboxReadyReadyPreviewCommentNov 13, 2025 11:27am

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds internal KeepPreviousDataFn and wiring so keepPreviousData affects React Query placeholderData in useSubscription and usePagesOrInfinite; adjusts pagination options passing and adds tests validating keepPreviousData true/false behavior. Also adds a changelog entry.

Changes

Cohort / File(s)Summary
Changelog Entry
/.changeset/soft-beers-sit.md
Adds a changelog entry describing a patch release that enables keepPreviousData behavior in the internal React Query variant of useSubscription.
Tests
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx
Adds two tests using a deferred promise to verify: (1) data is retained during refetch when keepPreviousData=true; (2) data is cleared during refetch when keepPreviousData=false.
Hook logic — usePagesOrInfinite
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx
Introduces an internal KeepPreviousDataFn<Data>(previousData: Data): Data and uses it as placeholderData when keepPreviousData is enabled.
Hook logic — useSubscription
packages/shared/src/react/hooks/useSubscription.rq.tsx
Adds the same internal KeepPreviousDataFn, reads params?.keepPreviousData into keepPreviousData, and sets placeholderData to the helper when enabled and queries are active.
Pagination config
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx
Changes how pagination options are passed to usePagesOrInfinite by spreading a wrapped object containing keepPreviousData and infinite and casting to PaginatedHookConfig<unknown> (typing adjustment, no behavior change).

Sequence Diagram(s)

sequenceDiagram
participant Consumer as Hook Consumer
participant Hook as useSubscription / usePagesOrInfinite
participant RQ as ReactQuery
Note over Hook,RQ: New internal helper KeepPreviousDataFn exists\nand is used as placeholderData when enabled
Consumer->>Hook: mount / trigger refetch (params.keepPreviousData = true|false)
Hook->>RQ: request data (config includes placeholderData = KeepPreviousDataFn or undefined)
alt keepPreviousData = true (queries enabled)
RQ-->>Consumer: returns previous data immediately (isFetching=true)
RQ->>Hook: final data arrives later (isFetching=false/isLoading=false)
Hook-->>Consumer: updates with new data
else keepPreviousData = false
RQ-->>Consumer: placeholder is undefined (isLoading=true)
RQ->>Hook: final data arrives later
Hook-->>Consumer: updates with new data
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring extra attention:
    • usePagesOrInfinite.rq.tsx and useSubscription.rq.tsx — ensure placeholderData integration preserves previous behavior and typing.
    • createBillingPaginatedHook.tsx — confirm the cast to PaginatedHookConfig<unknown> doesn't lose important type information.
    • New tests — validate reliability of deferred promise usage and timing assumptions.

Poem

🐇 I nibble code where queries play,

Previous crumbs I keep at bay,
When fetching runs, old carrots stay—
Then fresh sweet data hops my way. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and specifically describes the main change: adding support for keepPreviousData in useSubscription.rq, which is clearly reflected in the code changes to useSubscription.rq.tsx and related files.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/add-support-for-keep-previous-data-in-rq

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad91c39 and 85a1cb5.

📒 Files selected for processing (1)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/react/hooks/tests/useSubscription.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	packages/clerk-js/src/ui/contexts/components/Plans.tsx
#	packages/shared/src/react/hooks/useSubscription.rq.tsx
@panteliselefpanteliselef changed the title Elef/add support for keep previous data in rqfeat(shared): Support for keepPreviousData in useSubscription.rqNov 13, 2025

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

14-19: Duplicate helper function identified.

This KeepPreviousDataFn is identical to the one in useSubscription.rq.tsx. See the review comment on useSubscription.rq.tsx (lines 17-22) for the refactoring suggestion to extract this to a shared utility.

🧹 Nitpick comments (1)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)

17-22: Consider extracting KeepPreviousDataFn to a shared utility.

This function is duplicated identically in usePagesOrInfinite.rq.tsx (lines 14-19). Extract it to a shared location to follow DRY principles and simplify maintenance.

Consider creating a shared utility file:

// packages/shared/src/react/utils/reactQueryHelpers.ts/** * @internal */exportfunctionKeepPreviousDataFn<Data>(previousData: Data): Data{returnpreviousData;}

Then import it in both files:

+import { KeepPreviousDataFn } from '../utils/reactQueryHelpers';+-/**- * @internal- */-function KeepPreviousDataFn<Data>(previousData: Data): Data {- return previousData;-}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c63cc8e and ad91c39.

📒 Files selected for processing (5)
  • .changeset/soft-beers-sit.md (1 hunks)
  • packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (2 hunks)
  • packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1 hunks)
  • packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (2 hunks)
  • packages/shared/src/react/hooks/useSubscription.rq.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)
packages/shared/src/react/types.ts (1)
  • PaginatedHookConfig (89-102)
packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (4)
packages/shared/src/react/hooks/__tests__/mocks/clerk.ts (1)
  • createMockOrganization (61-63)
packages/shared/src/react/hooks/useSubscription.rq.tsx (1)
  • useSubscription (30-84)
packages/shared/src/react/hooks/useSubscription.swr.tsx (1)
  • useSubscription (22-71)
packages/shared/src/utils/createDeferredPromise.ts (1)
  • createDeferredPromise (11-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (8)
packages/shared/src/react/hooks/useSubscription.rq.tsx (2)

46-46: LGTM!

The extraction of keepPreviousData with a sensible default is clean and consistent with the codebase patterns.


70-70: LGTM!

The conditional logic correctly applies placeholderData only when both keepPreviousData is enabled and queries are active, preventing stale data retention when queries are disabled.

.changeset/soft-beers-sit.md (1)

1-5: LGTM!

The changelog entry clearly documents the new keepPreviousData feature and is correctly scoped as a patch-level change.

packages/shared/src/react/hooks/createBillingPaginatedHook.tsx (1)

108-111: Verify the necessity of the type cast.

The wrapping and casting to PaginatedHookConfig<unknown> suggests a type compatibility issue. While this should work at runtime, the unknown type parameter may be masking a type error or indicate that the generic type flow could be improved.

Consider investigating whether the type parameter can be more specific or if the wrapping/spreading pattern can be simplified:

// Current approach
...({keepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,}asPaginatedHookConfig<unknown>),// Alternative if types align properlykeepPreviousData: safeValues.keepPreviousData,infinite: safeValues.infinite,

If the cast is necessary due to type system limitations, consider adding a comment explaining why.

packages/shared/src/react/hooks/usePagesOrInfinite.rq.tsx (1)

75-75: LGTM!

The conditional placeholderData configuration correctly preserves previous data during pagination when keepPreviousData is enabled.

packages/shared/src/react/hooks/__tests__/useSubscription.spec.tsx (3)

4-4: LGTM!

The import of createDeferredPromise enables precise control over async timing in the new tests.


149-177: LGTM! Excellent test coverage.

This test thoroughly validates the keepPreviousData=true behavior:

  • Verifies previous data is retained during refetch (isFetching=true, isLoading=false)
  • Confirms data updates after the deferred promise resolves
  • Validates the correct number of fetcher invocations

The use of createDeferredPromise to control async timing is a solid testing pattern.


179-209: LGTM! Comprehensive test coverage.

This test effectively validates the keepPreviousData=false behavior:

  • Confirms data is cleared during refetch (isFetching=true, isLoading=true, data=undefined)
  • Verifies data populates after resolution
  • Validates correct fetcher call count

The test properly exercises the distinction between isLoading and isFetching states, which is important for React Query semantics.

@pkg-pr-new

pkg-pr-newBot commented Nov 13, 2025

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7203

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7203

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7203

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7203

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7203

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7203

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7203

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7203

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7203

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7203

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7203

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7203

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7203

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7203

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7203

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7203

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7203

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7203

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7203

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7203

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7203

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7203

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7203

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7203

commit: 85a1cb5

@panteliselef
panteliselef merged commit 42f0d95 into mainNov 13, 2025
71 of 77 checks passed
@panteliselef
panteliselef deleted the elef/add-support-for-keep-previous-data-in-rq branch November 13, 2025 14:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@panteliselef@bratsos@clerk-cookie