Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscription mode #1263

Merged
merged 31 commits into from Feb 24, 2023
Merged

Subscription mode #1263

merged 31 commits into from Feb 24, 2023

Conversation

huozhi
Copy link
Member

@huozhi huozhi commented Jul 2, 2021

To support subscription / disposable / observable data source, adding a new hook useSWRSubscription built on top of useSWR.

API

import type { Configuration } from 'swr'
import useSWRSupscription from 'swr/subscription'

useSWRSupscription(key, subscribe: SWRSubscription, config? Configuration)
export type SWRSubscription<Data = any, Error = any> = (
  key: Key,
  { next }: { next: (err?: Error | null, data?: Data) => void }
) => () => void

export type SWRSubscriptionResponse<Data = any, Error = any> = {
  data?: Data
  error?: Error
}

export type SWRSubscriptionHook<Data = any, Error = any> = (
  key: Key,
  subscribe: SWRSubscription<Data, Error>,
  config?: SWRConfiguration
) => SWRSubscriptionResponse<Data, Error>

the purpose is to provider users enough flexibility to manage their own subscription/disposable on user land, but still keep the argument shape different from function type fetcher.

Usage

function subscribe(key, { next }) {
  const unsubscribe = remoteSource.subscribe(
     (data) => next(null, data),
     (err) => next(err)
  )
  return () => unsubscribe()
}

const { data, error } = useSWRSubscription(key, subscribe)

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 2, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 54dfaee:

Sandbox Source
SWR-Basic Configuration
SWR-States Configuration
SWR-Infinite Configuration
SWR-SSR Configuration

@huozhi huozhi marked this pull request as draft July 2, 2021 05:06
@shuding shuding added this to the 1.0 milestone Jul 19, 2021
@huozhi huozhi marked this pull request as ready for review July 21, 2021 04:26
@shuding shuding modified the milestones: 1.0, backlog Aug 3, 2021
@huozhi huozhi added the on hold label Aug 17, 2021
@huozhi huozhi removed the on hold label Aug 28, 2021
@jamesalester
Copy link

Is this likely to get merged in soon? Subscriptions would be really useful for us

@huozhi
Copy link
Member Author

huozhi commented Sep 6, 2021

We're trying to get it into 1.1 or 1.2. But shortly we'd love to collect more use cases of subscription pattern in real world apps so that this API can be well abstract. If there're feedback from you would be very appreciated

@huozhi huozhi marked this pull request as draft September 6, 2021 14:30
@jamesalester
Copy link

Happy to help if I can. We're using subscriptions to have live data changes on multiple devices. We're using a graphql endpoint and currently have subscriptions set up like in this project. However, they don't handle the disposal of the websockets. I've been trying (and struggling) to implement my own disposal system using a similar hook to yours except it returns the dispose function with the data so that it can be called in the callback of a useEffect like:

const { data, error, dispose } = useSWRSubscribe(key, subscribeFn)

useEffect(() => {
  return () => {
    dispose()
  }
}, [])

@shuding
Copy link
Member

shuding commented Sep 6, 2021

Thanks! Yeah we still have a couple of concerns:

  • Should we leverage the new React useSyncExternalStore (useMutableSource) API?
  • In subscription mode, many of the SWR configs will be unusable (suspense, polling, error retry, ...), what should we do?
  • Should we provide APIs for manually pausing/stopping subscriptions?

Overall I think we can try to launch this in version 1.1/1.2 as an unstable API, and polish it overtime.

@jamesalester
Copy link

Should we leverage the new React useSyncExternalStore (useMutableSource) API?

At first glance this looks interesting and could be useful. I've not used it before though so would need to read deeper into it to understand it.

In subscription mode, many of the SWR configs will be unusable (suspense, polling, error retry, ...), what should we do?

I think the subscription mode would need its own set of config options. Some of those options wouldn't just be unusable but unnecessary too. I can't think of a reason why you would need to use polling with a subscription for example. For now it could just be a subset of the current SWR configs though it may need its own options adding in time.

Should we provide APIs for manually pausing/stopping subscriptions?

I could see this being useful though probably not necessary for an initial release.

I agree about launching this as an unstable API and polishing it over time.

@shuding shuding changed the title Subscribe mode Subscription mode Sep 21, 2021
@avisra
Copy link

avisra commented Jan 26, 2022

Is this still going to be delivered?

@huozhi huozhi marked this pull request as ready for review February 1, 2022 22:04
@huozhi huozhi requested a review from shuding February 1, 2022 22:04
@shuding
Copy link
Member

shuding commented Feb 2, 2022

Thank you for updating this! To push this forward, we need to set some minimal requirements to get this stable (under a flag or prefixed with unstable_). Here’re my thoughts:

  • It needs to use the useSyncExternalStore API under the hood, to guarantee the stability and correctness when rendering the UI concurrently. (This can be added in a future update)
  • Would be great if we change (onData, onError) => dispose to also support (callback: (error, data) => void, ...keys) => dispose, which follows the Node.js convention, but also passes the current keys. This aligns with the useSWR hook.

Copy link
Member

@shuding shuding left a comment

Choose a reason for hiding this comment

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

Looks like a good implementation for an initial unstable release! I think the ref counting approach should work with concurrent rendering, but let’s see..

subscribe/index.ts Outdated Show resolved Hide resolved
subscribe/index.ts Outdated Show resolved Hide resolved
@feledori
Copy link

I like the idea of this and i am currently trying to use SWR as a cache for WebSocket connections. In my use case I want to stash all incoming messages and use them as a log. With this current API I can only update the data with the incoming data. It would be nice if there was access to the current saved data through the next function to update the current data with old data and keep the cache. I don't know if this should be a use case for this hook and just wanted to give feedback. Thanks for the work on this.

@isBatak
Copy link

isBatak commented Jul 13, 2022

I like the idea of this and i am currently trying to use SWR as a cache for WebSocket connections. In my use case I want to stash all incoming messages and use them as a log. With this current API I can only update the data with the incoming data. It would be nice if there was access to the current saved data through the next function to update the current data with old data and keep the cache. I don't know if this should be a use case for this hook and just wanted to give feedback. Thanks for the work on this.

@feledori you can always save some complex object in the cache instead of array, something like:

const { data, mutate } = useSWRImmutable(key, async () => {
  const messages = await connection.getMessages();
  return { messages, incoming:[] };
});

useSWRSubscription(key, (key, { next }) => {  
  const handler = (newMessage) => {     
     next(undefined, { 
        messages:  [newMessage, ...data.messages], 
        incoming: [newMessage, ...data.incoming] 
    });
  }
  connection.on('messageAdd', handler);
  
  return () => {
      connection.off('messageAdd', handler);
  };
 });
 
 console.log(data.messages);
 console.log(data.incoming);

@koba04 koba04 removed this from the 2.0 milestone Jan 17, 2023
@huozhi huozhi mentioned this pull request Jan 20, 2023
@mike-shtil-loop
Copy link

@huozhi hey! Any info on which milestone will include this, following 2.0?

@karlo-humanmanaged
Copy link

Would love to see this merged! Is my assumption correct, that this can be used with grpc?

_internal/utils/mutate.ts Outdated Show resolved Hide resolved
subscription/index.ts Outdated Show resolved Hide resolved
subscription/index.ts Outdated Show resolved Hide resolved
subscription/index.ts Outdated Show resolved Hide resolved
subscription/index.ts Outdated Show resolved Hide resolved
Copy link
Member

@shuding shuding left a comment

Choose a reason for hiding this comment

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

Let's go!

@huozhi huozhi merged commit e5b5499 into main Feb 24, 2023
@huozhi huozhi deleted the subscribe branch February 24, 2023 19:06
kodiakhq bot pushed a commit to kula-app/OnLaunch that referenced this pull request Mar 15, 2023
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [swr](https://swr.vercel.app) ([source](https://togithub.com/vercel/swr)) | [`2.0.3` -> `2.1.0`](https://renovatebot.com/diffs/npm/swr/2.0.3/2.1.0) | [![age](https://badges.renovateapi.com/packages/npm/swr/2.1.0/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/npm/swr/2.1.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/npm/swr/2.1.0/compatibility-slim/2.0.3)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/npm/swr/2.1.0/confidence-slim/2.0.3)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>vercel/swr</summary>

### [`v2.1.0`](https://togithub.com/vercel/swr/releases/tag/v2.1.0)

[Compare Source](https://togithub.com/vercel/swr/compare/v2.0.4...v2.1.0)

#### Feature

-   Subscription mode by [@&#8203;huozhi](https://togithub.com/huozhi) in [vercel/swr#1263
-   parallel option for useSWRInfinite by [@&#8203;koba04](https://togithub.com/koba04) in [vercel/swr#2404

Checkout [subscription docs](https://swr.vercel.app/docs/subscription) and [useSWRInfinite parallel fetching docs](https://swr.vercel.app/docs/pagination#parallel-fetching-mode) for more details

#### Patches

-   fix: use the latest config in useSWRMutation by [@&#8203;koba04](https://togithub.com/koba04) in [vercel/swr#2468
-   Fix: type support for suspense and fallbackData([#&#8203;2396](https://togithub.com/vercel/swr/issues/2396)) by [@&#8203;taro-28](https://togithub.com/taro-28) in [vercel/swr#2452
-   Error should be reset when new data comes by [@&#8203;huozhi](https://togithub.com/huozhi) in [vercel/swr#2472
-   fix: avoid creating new snapshot if cache is not updated at client during streaming by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2475
-   refactor: initialize the cache only on first access by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2479

#### Misc

-   ci: fix publish workflow by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2453
-   ci: faster e2e test by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2428
-   test: add a test for keepPreviousData without changing key by [@&#8203;koba04](https://togithub.com/koba04) in [vercel/swr#2470
-   Always assume subscriptions will return sub count from current key by [@&#8203;huozhi](https://togithub.com/huozhi) in [vercel/swr#2460
-   test: Fix flaky e2e test by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2476
-   chore: Add subscription example by [@&#8203;huozhi](https://togithub.com/huozhi) in [vercel/swr#2480

#### New Contributors

-   [@&#8203;taro-28](https://togithub.com/taro-28) made their first contribution in [vercel/swr#2452

**Full Changelog**: vercel/swr@v2.0.4...v2.1.0

### [`v2.0.4`](https://togithub.com/vercel/swr/releases/tag/v2.0.4)

[Compare Source](https://togithub.com/vercel/swr/compare/v2.0.3...v2.0.4)

#### Patches

-   build: fix release job condition by [@&#8203;huozhi](https://togithub.com/huozhi) in [vercel/swr#2392
-   types: fix some mutation type issue by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2421
-   fix: Error retry should be handled by global revalidator instead of local revalidation function by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2415
-   fix: ensure initCache setter function stays within bounds of subscriptions by [@&#8203;lfbergee](https://togithub.com/lfbergee) in [vercel/swr#2411

#### Misc

-   test: stream ssr e2e by [@&#8203;promer94](https://togithub.com/promer94) in [vercel/swr#2395
-   test: fix an act warning by [@&#8203;koba04](https://togithub.com/koba04) in [vercel/swr#2403

#### New Contributors

-   [@&#8203;lfbergee](https://togithub.com/lfbergee) made their first contribution in [vercel/swr#2411

**Full Changelog**: vercel/swr@v2.0.3...v2.0.4

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/kula-app/OnLaunch).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS44LjMiLCJ1cGRhdGVkSW5WZXIiOiIzNS44LjMifQ==-->
renovate bot added a commit to Unleash/unleash that referenced this pull request May 4, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [swr](https://swr.vercel.app)
([source](https://togithub.com/vercel/swr)) | [`2.0.4` ->
`2.1.5`](https://renovatebot.com/diffs/npm/swr/2.0.4/2.1.5) |
[![age](https://badges.renovateapi.com/packages/npm/swr/2.1.5/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/npm/swr/2.1.5/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/npm/swr/2.1.5/compatibility-slim/2.0.4)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/npm/swr/2.1.5/confidence-slim/2.0.4)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>vercel/swr</summary>

### [`v2.1.5`](https://togithub.com/vercel/swr/releases/tag/v2.1.5)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.1.4...v2.1.5)

#### What's Changed

- fix: missing interop helpers in bundle by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2582

**Full Changelog**:
vercel/swr@v2.1.4...v2.1.5

### [`v2.1.4`](https://togithub.com/vercel/swr/releases/tag/v2.1.4)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.1.3...v2.1.4)

#### What's Changed

- Upgrade bundler by [@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2557
- examples: fix invalid links by
[@&#8203;fxOne](https://togithub.com/fxOne) in
[vercel/swr#2559
- types: Allow auto-import by improving generated types by
[@&#8203;oosawy](https://togithub.com/oosawy) in
[vercel/swr#2563
- fix: pass serialized args to preload fetcher by
[@&#8203;oosawy](https://togithub.com/oosawy) in
[vercel/swr#2564
- chore: use provenance for release by
[@&#8203;HerringtonDarkholme](https://togithub.com/HerringtonDarkholme)
in
[vercel/swr#2571
- deps: update
[@&#8203;testing-library/react](https://togithub.com/testing-library/react)
to v14 by [@&#8203;koba04](https://togithub.com/koba04) in
[vercel/swr#2578
- fix: Fix dependency tracking and useSES bug by
[@&#8203;shuding](https://togithub.com/shuding) and
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2576

#### New Contributors

- [@&#8203;fxOne](https://togithub.com/fxOne) made their first
contribution in
[vercel/swr#2559
- [@&#8203;oosawy](https://togithub.com/oosawy) made their first
contribution in
[vercel/swr#2563
-
[@&#8203;HerringtonDarkholme](https://togithub.com/HerringtonDarkholme)
made their first contribution in
[vercel/swr#2571

**Full Changelog**:
vercel/swr@v2.1.3...v2.1.4

### [`v2.1.3`](https://togithub.com/vercel/swr/releases/tag/v2.1.3)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.1.2...v2.1.3)

#### What's Changed

- Fix [#&#8203;2548](https://togithub.com/vercel/swr/issues/2548): pass
origin key to subcription callback by
[@&#8203;Zheaoli](https://togithub.com/Zheaoli) in
[vercel/swr#2550
- Examples: fix type in axios-typescript example by
[@&#8203;daochouwangu](https://togithub.com/daochouwangu) in
[vercel/swr#2552
- Update Cache Interface types by
[@&#8203;dmmulroy](https://togithub.com/dmmulroy) in
[vercel/swr#2554
- fix: data passed to refreshInterval function is not latest by
[@&#8203;hong24](https://togithub.com/hong24) in
[vercel/swr#2354
- types: allow passing function as `Data` for
`useSWRSubscriptionOptions` by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2551

#### New Contributors

- [@&#8203;Zheaoli](https://togithub.com/Zheaoli) made their first
contribution in
[vercel/swr#2550
- [@&#8203;daochouwangu](https://togithub.com/daochouwangu) made their
first contribution in
[vercel/swr#2552
- [@&#8203;dmmulroy](https://togithub.com/dmmulroy) made their first
contribution in
[vercel/swr#2554

**Full Changelog**:
vercel/swr@v2.1.2...v2.1.3

### [`v2.1.2`](https://togithub.com/vercel/swr/releases/tag/v2.1.2)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.1.1...v2.1.2)

##### Patches

-   Improved type inferring for `swr/subscription`
-   Adding `SWRSubscriptionOptions` type for `swr/subscription`

#### Changes

- test: add typing test for empty config by
[@&#8203;koba04](https://togithub.com/koba04) in
[vercel/swr#2521
- test: fix syntax error in Equal type alias implementation by
[@&#8203;SACHINnANYAKKARA](https://togithub.com/SACHINnANYAKKARA) in
[vercel/swr#2517
- chore: remove engines by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2536
- types: improve `useSWRSubscription` types by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2535
- Rename subscription types by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2537

#### New Contributors

- [@&#8203;SACHINnANYAKKARA](https://togithub.com/SACHINnANYAKKARA) made
their first contribution in
[vercel/swr#2517

**Full Changelog**:
vercel/swr@v2.1.1...v2.1.2

### [`v2.1.1`](https://togithub.com/vercel/swr/releases/tag/v2.1.1)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.1.0...v2.1.1)

#### Patches

- refactor: remove useless dataRef, always compare cached data by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2431
- fix: swr infers incorrect `data` type for default `SWRConfig` generic
type by [@&#8203;connorch](https://togithub.com/connorch) in
[vercel/swr#2506

#### Documentation

- docs: update subscription example by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2499

#### New Contributors

- [@&#8203;connorch](https://togithub.com/connorch) made their first
contribution in
[vercel/swr#2506

**Full Changelog**:
vercel/swr@v2.1.0...v2.1.1

### [`v2.1.0`](https://togithub.com/vercel/swr/releases/tag/v2.1.0)

[Compare
Source](https://togithub.com/vercel/swr/compare/v2.0.4...v2.1.0)

#### Feature

- Subscription mode by [@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#1263
- parallel option for useSWRInfinite by
[@&#8203;koba04](https://togithub.com/koba04) in
[vercel/swr#2404

Checkout [subscription docs](https://swr.vercel.app/docs/subscription)
and [useSWRInfinite parallel fetching
docs](https://swr.vercel.app/docs/pagination#parallel-fetching-mode) for
more details

#### Patches

- fix: use the latest config in useSWRMutation by
[@&#8203;koba04](https://togithub.com/koba04) in
[vercel/swr#2468
- Fix: type support for suspense and
fallbackData([#&#8203;2396](https://togithub.com/vercel/swr/issues/2396))
by [@&#8203;taro-28](https://togithub.com/taro-28) in
[vercel/swr#2452
- Error should be reset when new data comes by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2472
- fix: avoid creating new snapshot if cache is not updated at client
during streaming by [@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2475
- refactor: initialize the cache only on first access by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2479

#### Misc

- ci: fix publish workflow by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2453
- ci: faster e2e test by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2428
- test: add a test for keepPreviousData without changing key by
[@&#8203;koba04](https://togithub.com/koba04) in
[vercel/swr#2470
- Always assume subscriptions will return sub count from current key by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2460
- test: Fix flaky e2e test by
[@&#8203;promer94](https://togithub.com/promer94) in
[vercel/swr#2476
- chore: Add subscription example by
[@&#8203;huozhi](https://togithub.com/huozhi) in
[vercel/swr#2480

#### New Contributors

- [@&#8203;taro-28](https://togithub.com/taro-28) made their first
contribution in
[vercel/swr#2452

**Full Changelog**:
vercel/swr@v2.0.4...v2.1.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://app.renovatebot.com/dashboard#github/Unleash/unleash).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS42OS4zIiwidXBkYXRlZEluVmVyIjoiMzUuNjkuMyIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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.

None yet