Skip to content

Commit a89fc12

Browse files
committed
Merge remote-tracking branch 'origin/v5' into pr/4715
# Conflicts: # docs/react/guides/migrating-to-v5.md
2 parents b5df758 + 096da93 commit a89fc12

38 files changed

+173
-434
lines changed

.github/workflows/pr.yml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,6 @@ jobs:
6363
- name: Install dependencies
6464
run: pnpm --filter "./packages/**" --filter query --prefer-offline install
6565
- run: pnpm run test:format
66-
test-react-17:
67-
name: 'Test React 17'
68-
runs-on: ubuntu-latest
69-
steps:
70-
- uses: actions/checkout@v3
71-
- uses: pnpm/action-setup@v2.2.2
72-
with:
73-
version: 7
74-
- uses: actions/setup-node@v3
75-
with:
76-
node-version: 16.14.2
77-
cache: 'pnpm'
78-
- name: Install dependencies
79-
run: pnpm --filter "./packages/**" --filter query --prefer-offline install
80-
- run: pnpm run test:react:17
81-
env:
82-
REACTJS_VERSION: 17
8366
test-size:
8467
name: 'Size'
8568
runs-on: ubuntu-latest

docs/config.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,16 @@
177177
"to": "react/guides/does-this-replace-client-state"
178178
},
179179
{
180-
"label": "Migrating to React Query 3",
180+
"label": "Migrating to v3",
181181
"to": "react/guides/migrating-to-react-query-3"
182182
},
183183
{
184-
"label": "Migrating to React Query 4",
184+
"label": "Migrating to v4",
185185
"to": "react/guides/migrating-to-react-query-4"
186186
},
187187
{
188-
"label": "Migrating to React Query 5",
189-
"to": "react/guides/migrating-to-react-query-5"
188+
"label": "Migrating to v5",
189+
"to": "react/guides/migrating-v5"
190190
}
191191
]
192192
},

docs/react/guides/important-defaults.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ Out of the box, TanStack Query is configured with **aggressive but sane** defaul
1515
- The network is reconnected
1616
- The query is optionally configured with a refetch interval
1717

18-
If you see a refetch that you are not expecting, it is likely because you just focused the window and TanStack Query is doing a [`refetchOnWindowFocus`](../guides/window-focus-refetching). During development, this will probably be triggered more frequently, especially because focusing between the Browser DevTools and your app will also cause a fetch, so be aware of that.
19-
2018
> To change this functionality, you can use options like `refetchOnMount`, `refetchOnWindowFocus`, `refetchOnReconnect` and `refetchInterval`.
2119
2220
- Query results that have no more active instances of `useQuery`, `useInfiniteQuery` or query observers are labeled as "inactive" and remain in the cache in case they are used again at a later time.

docs/react/guides/migrating-to-react-query-5.md renamed to docs/react/guides/migrating-to-v5.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,22 @@ There are some caveats to this change however, which you must be aware of:
203203
}
204204
}, [dataUpdatedAt])
205205
```
206+
207+
### Window focus refetching no longer listens to the `focus` event
208+
209+
The `visibilitychange` event is used exclusively now. This is possible because we only support browsers that support the `visibilitychange` event. This fixes a bunch of issues [as listed here](https://github.com/TanStack/query/pull/4805).
210+
211+
### No longer using `unstable_batchedUpdates` as the batching function in React and React Native
212+
213+
Since the function `unstable_batchedUpdates` is noop in React 18, it will no longer be automatically set as the batching function in `react-query`.
214+
215+
If your framework supports a custom batching function, you can let TanStack Query know about it by calling `notifyManager.setBatchNotifyFunction`.
216+
217+
For example, this is how the batch function is set in `solid-query`:
218+
219+
```ts
220+
import { notifyManager } from '@tanstack/query-core'
221+
import { batch } from 'solid-js'
222+
223+
notifyManager.setBatchNotifyFunction(batch)
224+
```

docs/react/guides/window-focus-refetching.md

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,36 +48,19 @@ In rare circumstances, you may want to manage your own window focus events that
4848

4949
```tsx
5050
focusManager.setEventListener((handleFocus) => {
51-
// Listen to visibilitychange and focus
51+
// Listen to visibilitychange
5252
if (typeof window !== 'undefined' && window.addEventListener) {
5353
window.addEventListener('visibilitychange', handleFocus, false)
54-
window.addEventListener('focus', handleFocus, false)
5554
}
5655

5756
return () => {
5857
// Be sure to unsubscribe if a new handler is set
5958
window.removeEventListener('visibilitychange', handleFocus)
60-
window.removeEventListener('focus', handleFocus)
6159
}
6260
})
6361
```
6462

6563
[//]: # 'Example3'
66-
67-
## Ignoring Iframe Focus Events
68-
69-
A great use-case for replacing the focus handler is that of iframe events. Iframes present problems with detecting window focus by both double-firing events and also firing false-positive events when focusing or using iframes within your app. If you experience this, you should use an event handler that ignores these events as much as possible. I recommend [this one](https://gist.github.com/tannerlinsley/1d3a2122332107fcd8c9cc379be10d88)! It can be set up in the following way:
70-
71-
[//]: # 'Example4'
72-
73-
```tsx
74-
import { focusManager } from '@tanstack/react-query'
75-
import onWindowFocus from './onWindowFocus' // The gist above
76-
77-
focusManager.setEventListener(onWindowFocus) // Boom!
78-
```
79-
80-
[//]: # 'Example4'
8164
[//]: # 'ReactNative'
8265

8366
## Managing Focus in React Native
@@ -105,7 +88,7 @@ useEffect(() => {
10588

10689
## Managing focus state
10790

108-
[//]: # 'Example5'
91+
[//]: # 'Example4'
10992

11093
```tsx
11194
import { focusManager } from '@tanstack/react-query'
@@ -117,8 +100,4 @@ focusManager.setFocused(true)
117100
focusManager.setFocused(undefined)
118101
```
119102

120-
[//]: # 'Example5'
121-
122-
## Pitfalls & Caveats
123-
124-
Some browser internal dialogue windows, such as spawned by `alert()` or file upload dialogues (as created by `<input type="file" />`) might also trigger focus refetching after they close. This can result in unwanted side effects, as the refetching might trigger component unmounts or remounts before your file upload handler is executed. See [this issue on GitHub](https://github.com/tannerlinsley/react-query/issues/2960) for background and possible workarounds.
103+
[//]: # 'Example4'

docs/react/reference/focusManager.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ Its available methods are:
2020
```tsx
2121
import { focusManager } from '@tanstack/react-query'
2222

23-
focusManager.setEventListener(handleFocus => {
24-
// Listen to visibilitychange and focus
23+
focusManager.setEventListener((handleFocus) => {
24+
// Listen to visibilitychange
2525
if (typeof window !== 'undefined' && window.addEventListener) {
2626
window.addEventListener('visibilitychange', handleFocus, false)
27-
window.addEventListener('focus', handleFocus, false)
2827
}
2928

3029
return () => {
3130
// Be sure to unsubscribe if a new handler is set
3231
window.removeEventListener('visibilitychange', handleFocus)
33-
window.removeEventListener('focus', handleFocus)
3432
}
3533
})
3634
```

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"install:csb": "pnpm install --frozen-lockfile",
88
"test": "pnpm run test:ci",
99
"test:ci": "pnpm run test:format && pnpm run test:eslint && pnpm run test:jest --collectCoverage false && pnpm run typecheck",
10-
"test:react:17": "pnpm --filter \"./packages/react-*\" --parallel --no-bail run test:jest --collectCoverage false",
1110
"test:eslint": "pnpm --filter \"./packages/**\" --parallel --no-bail run test:eslint",
1211
"test:format": "pnpm run prettier --check",
1312
"test:jest": "pnpm --filter \"./packages/**\" --parallel --no-bail run test:jest",
@@ -35,7 +34,6 @@
3534
"@rollup/plugin-replace": "^4.0.0",
3635
"@testing-library/jest-dom": "^5.16.4",
3736
"@testing-library/react": "^13.0.0",
38-
"@testing-library/react-17": "npm:@testing-library/react@12.1.4",
3937
"@testing-library/react-hooks": "^7.0.2",
4038
"@tsconfig/svelte": "^3.0.0",
4139
"@types/jest": "^26.0.4",
@@ -75,9 +73,7 @@
7573
"luxon": "^2.3.2",
7674
"prettier": "^2.6.2",
7775
"react": "^18.2.0",
78-
"react-17": "npm:react@^17.0.2",
7976
"react-dom": "^18.2.0",
80-
"react-dom-17": "npm:react-dom@^17.0.2",
8177
"rollup": "^2.70.2",
8278
"rollup-plugin-size": "^0.2.2",
8379
"rollup-plugin-svelte": "^7.1.0",

packages/query-core/src/focusManager.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ export class FocusManager extends Subscribable {
1818
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1919
if (!isServer && window.addEventListener) {
2020
const listener = () => onFocus()
21-
// Listen to visibillitychange and focus
21+
// Listen to visibilitychange
2222
window.addEventListener('visibilitychange', listener, false)
23-
window.addEventListener('focus', listener, false)
2423

2524
return () => {
2625
// Be sure to unsubscribe if a new handler is set
2726
window.removeEventListener('visibilitychange', listener)
28-
window.removeEventListener('focus', listener)
2927
}
3028
}
3129
return

packages/query-core/src/query.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ export class Query<
159159
private observers: QueryObserver<any, any, any, any, any>[]
160160
private defaultOptions?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
161161
private abortSignalConsumed: boolean
162-
163162
constructor(config: QueryConfig<TQueryFnData, TError, TData, TQueryKey>) {
164163
super()
165164

@@ -174,11 +173,9 @@ export class Query<
174173
this.initialState = config.state || getDefaultState(this.options)
175174
this.state = this.initialState
176175
}
177-
178176
get meta(): QueryMeta | undefined {
179177
return this.options.meta
180178
}
181-
182179
private setOptions(
183180
options?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>,
184181
): void {

packages/query-core/src/queryCache.ts

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ interface QueryCacheConfig {
1515
onSuccess?: (data: unknown, query: Query<unknown, unknown, unknown>) => void
1616
}
1717

18-
interface QueryHashMap {
19-
[hash: string]: Query<any, any, any, any>
20-
}
21-
2218
interface NotifyEventQueryAdded {
2319
type: 'added'
2420
query: Query<any, any, any, any>
@@ -72,16 +68,10 @@ type QueryCacheListener = (event: QueryCacheNotifyEvent) => void
7268
// CLASS
7369

7470
export class QueryCache extends Subscribable<QueryCacheListener> {
75-
config: QueryCacheConfig
76-
77-
private queries: Query<any, any, any, any>[]
78-
private queriesMap: QueryHashMap
71+
private queries = new Map<string, Query>()
7972

80-
constructor(config?: QueryCacheConfig) {
73+
constructor(public config: QueryCacheConfig = {}) {
8174
super()
82-
this.config = config || {}
83-
this.queries = []
84-
this.queriesMap = {}
8575
}
8676

8777
build<TQueryFnData, TError, TData, TQueryKey extends QueryKey>(
@@ -111,9 +101,9 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
111101
}
112102

113103
add(query: Query<any, any, any, any>): void {
114-
if (!this.queriesMap[query.queryHash]) {
115-
this.queriesMap[query.queryHash] = query
116-
this.queries.push(query)
104+
if (!this.queries.has(query.queryHash)) {
105+
this.queries.set(query.queryHash, query)
106+
117107
this.notify({
118108
type: 'added',
119109
query,
@@ -122,15 +112,13 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
122112
}
123113

124114
remove(query: Query<any, any, any, any>): void {
125-
const queryInMap = this.queriesMap[query.queryHash]
115+
const queryInMap = this.queries.get(query.queryHash)
126116

127117
if (queryInMap) {
128118
query.destroy()
129119

130-
this.queries = this.queries.filter((x) => x !== query)
131-
132120
if (queryInMap === query) {
133-
delete this.queriesMap[query.queryHash]
121+
this.queries.delete(query.queryHash)
134122
}
135123

136124
this.notify({ type: 'removed', query })
@@ -139,7 +127,7 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
139127

140128
clear(): void {
141129
notifyManager.batch(() => {
142-
this.queries.forEach((query) => {
130+
this.getAll().forEach((query) => {
143131
this.remove(query)
144132
})
145133
})
@@ -149,15 +137,17 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
149137
TQueryFnData = unknown,
150138
TError = Error,
151139
TData = TQueryFnData,
152-
TQueyKey extends QueryKey = QueryKey,
140+
TQueryKey extends QueryKey = QueryKey,
153141
>(
154142
queryHash: string,
155-
): Query<TQueryFnData, TError, TData, TQueyKey> | undefined {
156-
return this.queriesMap[queryHash]
143+
): Query<TQueryFnData, TError, TData, TQueryKey> | undefined {
144+
return this.queries.get(queryHash) as
145+
| Query<TQueryFnData, TError, TData, TQueryKey>
146+
| undefined
157147
}
158148

159149
getAll(): Query[] {
160-
return this.queries
150+
return [...this.queries.values()]
161151
}
162152

163153
find<TQueryFnData = unknown, TError = Error, TData = TQueryFnData>(
@@ -167,13 +157,16 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
167157
filters.exact = true
168158
}
169159

170-
return this.queries.find((query) => matchQuery(filters, query))
160+
return this.getAll().find((query) => matchQuery(filters, query)) as
161+
| Query<TQueryFnData, TError, TData>
162+
| undefined
171163
}
172164

173165
findAll(filters: QueryFilters = {}): Query[] {
166+
const queries = this.getAll()
174167
return Object.keys(filters).length > 0
175-
? this.queries.filter((query) => matchQuery(filters, query))
176-
: this.queries
168+
? queries.filter((query) => matchQuery(filters, query))
169+
: queries
177170
}
178171

179172
notify(event: QueryCacheNotifyEvent) {
@@ -186,15 +179,15 @@ export class QueryCache extends Subscribable<QueryCacheListener> {
186179

187180
onFocus(): void {
188181
notifyManager.batch(() => {
189-
this.queries.forEach((query) => {
182+
this.getAll().forEach((query) => {
190183
query.onFocus()
191184
})
192185
})
193186
}
194187

195188
onOnline(): void {
196189
notifyManager.batch(() => {
197-
this.queries.forEach((query) => {
190+
this.getAll().forEach((query) => {
198191
query.onOnline()
199192
})
200193
})

0 commit comments

Comments
 (0)