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
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cbf8752
update subscribe with middleware
huozhi Jul 2, 2021
af89adb
fix lint & test
huozhi Jul 19, 2021
7283270
update typing, fix test and lint
huozhi Feb 1, 2022
bfa9056
refactor callback, rename, use refs for callbacks
huozhi Feb 3, 2022
510524a
Delay unmount
huozhi Feb 3, 2022
abfa159
Merge branch 'main' into subscribe
huozhi Feb 3, 2022
8ed9d72
Merge branch 'main' into subscribe
huozhi Apr 5, 2022
8f48cce
Merge branch 'main' into subscribe
huozhi Apr 12, 2022
8cfc3f5
no swr destruction and add getters, revert pkg.json
huozhi Apr 16, 2022
c023e89
callback -> next
huozhi Apr 17, 2022
2f33952
rename fix types and update test
huozhi Apr 17, 2022
138ede4
change exports to unstable_subscription
huozhi Apr 19, 2022
350f022
Merge branch 'main' into subscribe
huozhi May 17, 2022
7ad1935
manage subs with useESE
huozhi May 17, 2022
beaf868
use serialize
huozhi May 18, 2022
0e873eb
merge canary
huozhi Sep 22, 2022
81e2ab1
Merge branch 'main' into subscribe
huozhi Jan 23, 2023
4753152
fix lint
huozhi Jan 23, 2023
401738c
use cache helper to update error
huozhi Jan 24, 2023
6aed4ea
update exports path
huozhi Jan 26, 2023
ca2668b
fix script
huozhi Feb 1, 2023
c0ab66e
Merge branch 'main' into subscribe
huozhi Feb 1, 2023
8276703
pub check
huozhi Feb 1, 2023
c21aa98
add exp jsdoc
huozhi Feb 24, 2023
1c2b974
use cache-scoped storage
shuding Feb 24, 2023
5656fef
use prefixed key; add more tests
shuding Feb 24, 2023
12e3111
fix type
shuding Feb 24, 2023
0c04bfd
remove subscriber ref
shuding Feb 24, 2023
73ffb1c
rename
shuding Feb 24, 2023
7963ae8
fix lint
huozhi Feb 24, 2023
54dfaee
Merge branch 'main' into subscribe
huozhi Feb 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion immutable/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swr-immutable",
"version": "0.0.1",
"private": true,
shuding marked this conversation as resolved.
Show resolved Hide resolved
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
"types": "./dist/immutable",
Expand Down
2 changes: 1 addition & 1 deletion infinite/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swr-infinite",
"version": "0.0.1",
"private": true,
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
"types": "./dist/infinite",
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module.exports = {
moduleNameMapper: {
'^swr$': '<rootDir>/src',
'^swr/infinite$': '<rootDir>/infinite/index.ts',
'^swr/immutable$': '<rootDir>/immutable/index.ts'
'^swr/immutable$': '<rootDir>/immutable/index.ts',
'^swr/subscribe$': '<rootDir>/subscribe/index.ts',
},
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest'
Expand Down
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,39 @@
"module": "./immutable/dist/index.esm.js",
"require": "./immutable/dist/index.js",
"types": "./immutable/dist/immutable/index.d.ts"
},
"./subscribe": {
"import": "./subscribe/dist/index.mjs",
"module": "./subscribe/dist/index.esm.js",
"require": "./subscribe/dist/index.js",
"types": "./subscribe/dist/subscribe/index.d.ts"
}
},
"types": "./dist/index.d.ts",
"files": [
"dist/**",
"infinite/dist/**",
"immutable/dist/**",
"subscribe/dist/**",
"infinite/package.json",
"immutable/package.json"
"immutable/package.json",
"subscribe/package.json"
],
"repository": "github:vercel/swr",
"homepage": "https://swr.vercel.app",
"license": "MIT",
"scripts": {
"clean": "rimraf dist infinite/dist immutable/dist",
"build": "yarn build:core && yarn build:infinite && yarn build:immutable",
"build": "yarn build:core && yarn build:infinite && yarn build:immutable && yarn build:subscribe",
"watch": "npm-run-all -p watch:core watch:infinite watch:immutable",
"watch:core": "yarn build:core -w",
"watch:infinite": "yarn build:infinite -w",
"watch:immutable": "yarn build:immutable -w",
"watch:subscribe": "yarn build:subscribe -w",
"build:core": "bunchee src/index.ts --no-sourcemap",
"build:infinite": "bunchee index.ts --cwd infinite --no-sourcemap",
"build:immutable": "bunchee index.ts --cwd immutable --no-sourcemap",
"build:subscribe": "bunchee index.ts --cwd subscribe --no-sourcemap",
"prepublishOnly": "yarn clean && yarn build",
"publish-beta": "yarn publish --tag beta",
"types:check": "tsc --noEmit --project tsconfig.check.json && tsc --noEmit -p test",
Expand Down
70 changes: 70 additions & 0 deletions subscribe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useEffect } from 'react'
import useSWR from 'swr'
import { withMiddleware } from '../src/utils/with-middleware'
import { Key, SWRHook, Middleware, SWRConfiguration } from '../src/types'

export type SWRSubscription<Data = any, Error = any> = (
key: Key,
callbacks: {
onData(data: Data): void
onError(err: Error): void
}
) => void

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

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

const subscriptions = new Map<Key, number>()
const disposers = new Map()

export const subscribe = (<Data, Error>(useSWRNext: SWRHook) =>
(
key: Key,
subscribeFn: SWRSubscription<Data, Error>,
config?: SWRConfiguration
): SWRSubscriptionResponse<Data, Error> => {
const { data, error, mutate } = useSWRNext(key, null, config)

useEffect(() => {
subscriptions.set(key, (subscriptions.get(key) || 0) + 1)
const onData = (val: Data) => mutate(val, false)
const onError = async (err: any) => {
// Avoid thrown errors from `mutate`
// eslint-disable-next-line no-empty
try {
await mutate(() => {
throw err
}, false)
} catch (_) {
/* eslint-disable-line no-empty */
}
}

if (subscriptions.get(key) === 1) {
const dispose = subscribeFn(key, { onData, onError })
disposers.set(key, dispose)
}
return () => {
huozhi marked this conversation as resolved.
Show resolved Hide resolved
const count = subscriptions.get(key) || 1
subscriptions.set(key, count - 1)
// dispose if it's last one
if (count === 1) {
disposers.get(key)()
}
}
}, [key, mutate, subscribeFn])
huozhi marked this conversation as resolved.
Show resolved Hide resolved

return { data, error }
}) as Middleware

const useSWRSubscribe = withMiddleware(useSWR, subscribe) as SWRSubscriptionHook

export { useSWRSubscribe as unstable_useSWRSubscribe }
12 changes: 12 additions & 0 deletions subscribe/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "swr-subscribe",
"private": true,
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
"types": "./dist/subscribe",
"exports": "./dist/index.mjs",
"peerDependencies": {
"swr": "*",
"react": "*"
}
}
9 changes: 9 additions & 0 deletions subscribe/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "..",
},
"include": [".", "../src"],
"exclude": ["./dist"]
}
47 changes: 47 additions & 0 deletions test/use-swr-subscribe.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react'
import { act, screen } from '@testing-library/react'
import { sleep, renderWithConfig } from './utils'
import { unstable_useSWRSubscribe as useSWRSubscription } from 'swr/subscribe'

describe('useSWRSubscription', () => {
it('should update state when fetcher is a subscription', async () => {
const key = 'sub-0'
let intervalId
let res = 0
function subscribe(_key, { onData, onError }) {
intervalId = setInterval(() => {
if (res === 3) {
const err = new Error(_key + 'error')
onError(err)
} else {
onData(_key + res)
}
res++
}, 100)

return () => {}
}

function Page() {
const { data, error } = useSWRSubscription(key, subscribe, {
fallbackData: 'fallback'
})
return <div>{error ? error.message : data}</div>
}

renderWithConfig(<Page />)
await act(() => sleep(10))
screen.getByText(`fallback`)
await act(() => sleep(100))
screen.getByText(`${key}0`)
await act(() => sleep(100))
screen.getByText(`${key}1`)
await act(() => sleep(100))
screen.getByText(`${key}2`)
await act(() => sleep(100))
screen.getByText(`${key}error`)
clearInterval(intervalId)
await sleep(100)
screen.getByText(`${key}error`)
})
})
2 changes: 1 addition & 1 deletion tsconfig.check.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"compilerOptions": {
"rootDir": ".",
},
"include": ["src", "immutable", "infinite"]
"include": ["src", "immutable", "infinite", "subscribe"]
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"paths": {
"swr": ["./src/index.ts"],
"swr/infinite": ["./infinite/index.ts"],
"swr/immutable": ["./immutable/index.ts"]
"swr/immutable": ["./immutable/index.ts"],
"swr/subscribe": ["./subscribe/index.ts"],
},
"typeRoots": ["./src/types", "./node_modules/@types"]
},
Expand Down