Skip to content

Commit

Permalink
(suspense) - Fix suspenseExchange affecting subscriptions and add dep…
Browse files Browse the repository at this point in the history
…recation note (#789)

* Fix suspenseExchange being applied to subscriptions

Subscription Operations are never subject to suspense-mode.

* Add deprecation note
  • Loading branch information
kitten authored May 5, 2020
1 parent 3f46ae8 commit bde241f
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/red-brooms-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/exchange-suspense': minor
---

Add deprecation notice, as exchange isn't as useful as expected and unstable
5 changes: 5 additions & 0 deletions .changeset/tiny-ducks-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/exchange-suspense': patch
---

Fix subscription operations from being affected by the `suspenseExchange`.
29 changes: 9 additions & 20 deletions exchanges/suspense/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
<h2 align="center">@urql/exchange-suspense</h2>
<h2 align="center">@urql/exchange-suspense <strong>(deprecated)</strong></h2>
<p align="center">
<strong>An exchange for client-side React Suspense support in <code>urql</code></strong>
<br /><br />
<a href="https://npmjs.com/package/@urql/exchange-suspense">
<img alt="NPM Version" src="https://img.shields.io/npm/v/@urql/exchange-suspense.svg" />
</a>
<a href="https://bundlephobia.com/result?p=@urql/exchange-suspense">
<img alt="Minified gzip size"
src="https://img.shields.io/bundlephobia/minzip/@urql/exchange-suspense.svg?label=gzip%20size" />
</a>
<a href="https://github.com/FormidableLabs/urql-exchange-suspense#maintenance-status">
<img alt="Maintenance Status" src="https://img.shields.io/badge/maintenance-experimental-blueviolet.svg" />
</a>
</p>
<br />

`@urql/exchange-suspense` is an exchange for the [`urql`](../../README.md) GraphQL client that allows the
use of React Suspense on the client-side with `urql`'s built-in suspense mode.
Expand All @@ -23,10 +13,13 @@ suspense on the server.
But since `<Suspense>` is mainly intended for client-side use it made sense to build and publish
this exchange, which allows you to try out `urql` and suspense in your React app!

> ⚠️ Note: React's Suspense feature is currently unstable and may still change.
> This exchange is experimental and demonstrates how `urql` already supports and
> interacts with client-side suspense and how it may behave in the future, when React
> Suspense ships and becomes stable. You may use it, but do so at your own risk!
> ⚠️ **\*Deprecated**:
> This package is deprecated! Usage of client-side suspense with `urql` isn't recommended anymore
> and this packages has been marked as _deprecated_ after being _experimental_, since all it allows
> for is to use Suspense as a fancier loading boundary, which isn't its intended use.
> This exchange may still be useful when used with care, but it's worth keeping in mind that the
> suspense patterns in `urql` for the client-side may change.
> Suspense-mode usage for SSR remains unchanged and undeprecated however.
## Quick Start Guide

Expand Down Expand Up @@ -157,7 +150,3 @@ const client = createClient({
].filter(Boolean),
});
```

## Maintenance Status

**Experimental:** This project is quite new. We're not sure what our ongoing maintenance plan for this project will be. Bug reports, feature requests and pull requests are welcome. If you like this project, let us know by starring the repo!
24 changes: 12 additions & 12 deletions exchanges/suspense/src/suspenseExchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import { Exchange, OperationResult, Operation } from '@urql/core';
type SuspenseCache = Map<number, OperationResult>;
type SuspenseKeys = Set<number>;

const shouldSkip = ({ operationName }: Operation) =>
operationName !== 'subscription' && operationName !== 'query';

export const suspenseExchange: Exchange = ({ client, forward }) => {
// Warn and disable the suspenseExchange when the client's suspense mode isn't enabled
if (!client.suspense) {
Expand Down Expand Up @@ -35,9 +32,9 @@ export const suspenseExchange: Exchange = ({ client, forward }) => {
// Every uncached operation that isn't skipped will be marked as immediate and forwarded
const forwardResults$ = pipe(
sharedOps$,
filter(op => shouldSkip(op) || !isOperationCached(op)),
filter(op => op.operationName !== 'query' || !isOperationCached(op)),
onPush(op => {
if (!shouldSkip(op)) keys.add(op.key);
if (op.operationName === 'query') keys.add(op.key);
}),
forward,
share
Expand All @@ -46,15 +43,18 @@ export const suspenseExchange: Exchange = ({ client, forward }) => {
// Results that are skipped by suspense (mutations)
const ignoredResults$ = pipe(
forwardResults$,
filter(res => shouldSkip(res.operation))
filter(res => res.operation.operationName !== 'query')
);

// Results that may have suspended since they did not resolve synchronously
const deferredResults$ = pipe(
forwardResults$,
filter(
res => !shouldSkip(res.operation) && !isOperationCached(res.operation)
),
filter(res => {
return (
res.operation.operationName === 'query' &&
!isOperationCached(res.operation)
);
}),
onPush((res: OperationResult) => {
const { key } = res.operation;
keys.delete(key);
Expand All @@ -70,9 +70,9 @@ export const suspenseExchange: Exchange = ({ client, forward }) => {
// deferredResults$ ignores it
const immediateResults$ = pipe(
sharedOps$,
filter(op => !shouldSkip(op) && !isOperationCached(op)),
filter(op => op.operationName === 'query' && !isOperationCached(op)),
onPush(op => {
if (!shouldSkip(op)) keys.delete(op.key);
if (op.operationName === 'query') keys.delete(op.key);
}),
filter<any>(() => false)
);
Expand All @@ -81,7 +81,7 @@ export const suspenseExchange: Exchange = ({ client, forward }) => {
// by the suspenseExchange, and will be deleted from the cache immediately after
const cachedResults$ = pipe(
sharedOps$,
filter(op => !shouldSkip(op) && isOperationCached(op)),
filter(op => op.operationName === 'query' && isOperationCached(op)),
map(op => {
const { key } = op;
const result = cache.get(key) as OperationResult;
Expand Down

0 comments on commit bde241f

Please sign in to comment.