Skip to content

fix(subscription): support async subscribe function in useSWRSubscription - #4345

Open
wasim-builds wants to merge 1 commit into
vercel:mainfrom
wasim-builds:fix/subscription-async-cleanup
Open

wasim-builds wants to merge 1 commit into
vercel:mainfrom
wasim-builds:fix/subscription-async-cleanup

Conversation

@wasim-builds

Copy link
Copy Markdown

Description

Closes #4214

Problem

Previously, useSWRSubscription executed subscribe(args, { next }) synchronously and asserted that the returned disposer was a function via if (typeof dispose !== 'function') throw new Error(...). When subscribe is an async function, it returns a Promise instead of an unsubscribe function, causing the hook to immediately throw an error. In addition, any cleanup function returned upon promise resolution was never registered or called, causing connection and memory leaks.

Root Cause

  1. SWRSubscription type in src/subscription/types.ts did not explicitly type Promise<(() => void) | void> as an allowed return type.
  2. In src/subscription/index.ts, subscribe was assumed to return a synchronous cleanup function. Promise returns were treated as invalid return values, and asynchronous resolution and unmount cleanup lifecycles were not handled.

Fix

  1. Updated SWRSubscription in src/subscription/types.ts to allow (() => void) | void | Promise<(() => void) | void> as return types.
  2. In src/subscription/index.ts:
    • Supported Promise returns (dispose && typeof dispose.then === 'function').
    • Tracked unmount state with a disposer flag. If the component or last subscriber unmounts before the async subscribe promise resolves, the returned cleanup function is immediately invoked upon settlement to prevent connection leaks.
    • If still mounted, the resolved cleanup function is registered in disposers.
    • Handled promise rejections by forwarding errors to next(error) if the subscription remains active.
    • Preserved synchronous cleanup functions and allowed void returns.
  3. Added unit tests in test/use-swr-subscription.test.tsx verifying:
    • Async subscribe function with cleanup function called on unmount.
    • Async subscribe function where unmount occurs before promise resolves (immediate cleanup on resolution).
    • Async subscribe function returning void without throwing on unmount.
    • Async subscribe function rejection forwarding error to next.
    • Deduplication across multiple subscribers with async subscribe functions.

Verification

  • pnpm jest test/use-swr-subscription.test.tsx: 1 passed, 13 passed, 13 total.
  • pnpm test-typing: Clean pass.
  • pnpm test: 36 passed, 402 passed, 5 skipped, 407 total.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 07:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

This branch has not been deployed

No deployments
Sign up for free to 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.

useSWRSubscription does not work with async subscribe function

2 participants