Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions broadcastQueryClient-experimental/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"internal": true,
"main": "../lib/broadcastQueryClient-experimental/index.js",
"module": "../es/broadcastQueryClient-experimental/index.js",
"types": "../types/broadcastQueryClient-experimental/index.d.ts"
}
59 changes: 59 additions & 0 deletions docs/src/pages/plugins/broadcastQueryClient.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
id: broadcastQueryClient
title: broadcastQueryClient (Experimental)
---

> VERY IMPORTANT: This utility is currently in an experimental stage. This means that breaking changes will happen in minor AND patch releases. Use at your own risk. If you choose to rely on this in production in an experimental stage, please lock your version to a patch-level version to avoid unexpected breakages.

`broadcastQueryClient` is a utility for broadcasting and syncing the state of your queryClient between browser tabs/windows with the same origin.

## Installation

This utility comes packaged with `react-query` and is available under the `react-query/broadcastQueryClient-experimental` import.

## Usage

Import the `broadcastQueryClient` function, and pass it your `QueryClient` instance, and optionally, set a `broadcastChannel`.

```ts
import { broadcastQueryClient } from 'react-query/broadcastQueryClient-experimental'

const queryClient = new QueryClient()

broadcastQueryClient({
queryClient,
broadcastChannel: 'my-app',
})
```

## API

### `broadcastQueryClient`

Pass this function a `QueryClient` instance and optionally, a `broadcastChannel`.

```ts
broadcastQueryClient({ queryClient, broadcastChannel })
```

### `Options`

An object of options:

```ts
interface broadcastQueryClient {
/** The QueryClient to sync */
queryClient: QueryClient
/** This is the unique channel name that will be used
* to communicate between tabs and windows */
broadcastChannel?: string
}
```

The default options are:

```ts
{
broadcastChannel = 'react-query',
}
```
1 change: 1 addition & 0 deletions examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"dependencies": {
"axios": "^0.21.1",
"broadcast-channel": "^3.4.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-query": "^3.5.0",
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@
"devtools",
"persistQueryClient-experimental",
"createLocalStoragePersistor-experimental",
"broadcastQueryClient-experimental",
"lib",
"react",
"scripts",
"types"
],
"dependencies": {
"@babel/runtime": "^7.5.5",
"broadcast-channel": "^3.4.1",
"match-sorter": "^6.0.2"
},
"peerDependencies": {
Expand Down
5 changes: 5 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ const inputSrcs = [
'ReactQueryCreateLocalStoragePersistorExperimental',
'createLocalStoragePersistor-experimental',
],
[
'src/broadcastQueryClient-experimental/index.ts',
'ReactQueryBroadcastQueryClientExperimental',
'broadcastQueryClient-experimental',
],
]

const extensions = ['.js', '.jsx', '.es6', '.es', '.mjs', '.ts', '.tsx']
Expand Down
89 changes: 89 additions & 0 deletions src/broadcastQueryClient-experimental/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { BroadcastChannel } from 'broadcast-channel'
import { QueryClient } from '../core'

interface BroadcastQueryClientOptions {
queryClient: QueryClient
broadcastChannel: string
}

export function broadcastQueryClient({
queryClient,
broadcastChannel = 'react-query',
}: BroadcastQueryClientOptions) {
let transaction = false
const tx = (cb: () => void) => {
transaction = true
cb()
transaction = false
}

const channel = new BroadcastChannel(broadcastChannel, {
webWorkerSupport: false,
})

const queryCache = queryClient.getQueryCache()

queryClient.getQueryCache().subscribe(queryEvent => {
if (transaction || !queryEvent?.query) {
return
}

const {
query: { queryHash, queryKey, state },
} = queryEvent

if (
queryEvent.type === 'queryUpdated' &&
queryEvent.action?.type === 'success'
) {
channel.postMessage({
type: 'queryUpdated',
queryHash,
queryKey,
state,
})
}

if (queryEvent.type === 'queryRemoved') {
channel.postMessage({
type: 'queryRemoved',
queryHash,
queryKey,
})
}
})

channel.onmessage = action => {
if (!action?.type) {
return
}

tx(() => {
const { type, queryHash, queryKey, state } = action

if (type === 'queryUpdated') {
const query = queryCache.get(queryHash)

if (query) {
query.setState(state)
return
}

queryCache.build(
queryClient,
{
queryKey,
queryHash,
},
state
)
} else if (type === 'queryRemoved') {
const query = queryCache.get(queryHash)

if (query) {
queryCache.remove(query)
}
}
})
}
}
12 changes: 10 additions & 2 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ interface ContinueAction {
interface SetStateAction<TData, TError> {
type: 'setState'
state: QueryState<TData, TError>
setStateOptions?: SetStateOptions
}

export type Action<TData, TError> =
Expand All @@ -118,6 +119,10 @@ export type Action<TData, TError> =
| SetStateAction<TData, TError>
| SuccessAction<TData>

export interface SetStateOptions {
meta?: any
}

// CLASS

export class Query<
Expand Down Expand Up @@ -216,8 +221,11 @@ export class Query<
return data
}

setState(state: QueryState<TData, TError>): void {
this.dispatch({ type: 'setState', state })
setState(
state: QueryState<TData, TError>,
setStateOptions?: SetStateOptions
): void {
this.dispatch({ type: 'setState', state, setStateOptions })
}

cancel(options?: CancelOptions): Promise<void> {
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.types.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"./src/hydration/index.ts",
"./src/devtools/index.ts",
"./src/persistQueryClient-experimental/index.ts",
"./src/createLocalStoragePersistor-experimental/index.ts"
"./src/createLocalStoragePersistor-experimental/index.ts",
"./src/broadcastQueryClient-experimental/index.ts"
],
"exclude": ["./src/**/*"]
}
57 changes: 56 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1944,6 +1944,13 @@
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2":
version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d"
integrity sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.8.4":
version "7.10.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
Expand Down Expand Up @@ -3088,6 +3095,11 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"

big-integer@^1.6.16:
version "1.6.48"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==

binary-extensions@^1.0.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
Expand Down Expand Up @@ -3136,6 +3148,19 @@ braces@^3.0.1:
dependencies:
fill-range "^7.0.1"

broadcast-channel@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.4.1.tgz#65b63068d0a5216026a19905c9b2d5e9adf0928a"
integrity sha512-VXYivSkuBeQY+pL5hNQQNvBdKKQINBAROm4G8lAbWQfOZ7Yn4TMcgLNlJyEqlkxy5G8JJBsI3VJ1u8FUTOROcg==
dependencies:
"@babel/runtime" "^7.7.2"
detect-node "^2.0.4"
js-sha3 "0.8.0"
microseconds "0.2.0"
nano-time "1.0.0"
rimraf "3.0.2"
unload "2.2.0"

brotli-size@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/brotli-size/-/brotli-size-4.0.0.tgz#a05ee3faad3c0e700a2f2da826ba6b4d76e69e5e"
Expand Down Expand Up @@ -3652,6 +3677,11 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==

detect-node@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==

diff-sequences@^25.2.6:
version "25.2.6"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
Expand Down Expand Up @@ -5468,6 +5498,11 @@ jest@^26.0.1:
import-local "^3.0.2"
jest-cli "^26.0.1"

js-sha3@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==

"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
Expand Down Expand Up @@ -5863,6 +5898,11 @@ micromatch@^4.0.2:
braces "^3.0.1"
picomatch "^2.0.5"

microseconds@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==

mime-db@1.42.0:
version "1.42.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac"
Expand Down Expand Up @@ -5945,6 +5985,13 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==

nano-time@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=
dependencies:
big-integer "^1.6.16"

nanoid@^3.0.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.3.tgz#b2bcfcfda4b4d6838bc22a0c8dd3c0a17a204c20"
Expand Down Expand Up @@ -6823,7 +6870,7 @@ rimraf@2.6.3:
dependencies:
glob "^7.1.3"

rimraf@^3.0.0, rimraf@^3.0.2:
rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
Expand Down Expand Up @@ -7755,6 +7802,14 @@ universalify@^0.1.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==

unload@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
dependencies:
"@babel/runtime" "^7.6.2"
detect-node "^2.0.4"

unquote@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
Expand Down