Skip to content

Commit 9e23e7a

Browse files
authored
fix(persistQueryClient): rename isHydrating to isRestoring (#3512)
* fix(devtools): devtools should not import relatively from react-query * fix(hydration): properly remove unused hydration entry point hydration moved to the core, and the build entry point was already removed for v4. this is just a proper cleanup. * fix(persistQueryClient): rename isHydrating to isRestoring as we currently have no plans to re-use this for useHydrate, it would be confusing to not get true for this value in those cases * fix(persistQueryClient): document useIsRestoring * fix: make QueryErrorResetBoundary value stable we want a constant value for the lifetime of the QueryErrorResetBoundary component; useMemo doesn't guarantee that. * chore: remove resolutions from package.json as discussed here: #2688 (comment) * fix: log message we don't have a queryKey at this point if a string was used due to how the overloads try to spread things * Update docs/src/pages/plugins/persistQueryClient.md
1 parent a8ddd9b commit 9e23e7a

File tree

16 files changed

+40
-54
lines changed

16 files changed

+40
-54
lines changed

docs/src/pages/plugins/persistQueryClient.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ ReactDOM.createRoot(rootElement).render(
220220
- will be called when the initial restore is finished
221221
- can be used to [resumePausedMutations](../reference/QueryClient#queryclientresumepausedmutations)
222222

223+
### useIsRestoring
224+
225+
If you are using the `PersistQueryClientProvider`, you can also use the `useIsRestoring` hook alongside it to check if a restore is currently in progress. `useQuery` and friends also check this internally to avoid race conditions between the restore and mounting queries.
226+
223227
## Persisters
224228

225229
### Persisters Interface

examples/offline/src/App.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
QueryClient,
66
MutationCache,
77
onlineManager,
8-
useIsHydrating,
8+
useisRestoring,
99
} from "react-query";
1010
import { ReactQueryDevtools } from "react-query/devtools";
1111
import toast, { Toaster } from "react-hot-toast";
@@ -76,7 +76,7 @@ export default function App() {
7676
}
7777

7878
function Movies() {
79-
const isHydrating = useIsHydrating();
79+
const isRestoring = isRestoring();
8080
return (
8181
<Router
8282
location={location}
@@ -93,7 +93,7 @@ function Movies() {
9393
queryClient.getQueryData(movieKeys.detail(movieId)) ??
9494
// do not load if we are offline or hydrating because it returns a promise that is pending until we go online again
9595
// we just let the Detail component handle it
96-
(onlineManager.isOnline() && !isHydrating
96+
(onlineManager.isOnline() && !isRestoring
9797
? queryClient.fetchQuery(movieKeys.detail(movieId), () =>
9898
api.fetchMovie(movieId)
9999
)

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,6 @@
147147
"type-fest": "^0.21.0",
148148
"typescript": "4.5.3"
149149
},
150-
"resolutions": {
151-
"@types/react": "^16.9.41",
152-
"@types/react-dom": "^16.9.8"
153-
},
154150
"bundlewatch": {
155151
"files": [
156152
{

src/core/query.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,7 @@ export class Query<
366366
if (!Array.isArray(this.options.queryKey)) {
367367
if (process.env.NODE_ENV !== 'production') {
368368
this.logger.error(
369-
'As of v4, queryKey needs to be an Array, but the queryKey used was:',
370-
JSON.stringify(this.options.queryKey)
369+
`As of v4, queryKey needs to be an Array. If you are using a string like 'repoData', please change it to an Array, e.g. ['repoData']`
371370
)
372371
}
373372
}

src/core/queryObserver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ export class QueryObserver<
439439
status = 'loading'
440440
}
441441
}
442-
if (options._optimisticResults === 'isHydrating') {
442+
if (options._optimisticResults === 'isRestoring') {
443443
fetchStatus = 'idle'
444444
}
445445
}

src/core/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export interface QueryObserverOptions<
231231
*/
232232
placeholderData?: TQueryData | PlaceholderDataFunction<TQueryData>
233233

234-
_optimisticResults?: 'optimistic' | 'isHydrating'
234+
_optimisticResults?: 'optimistic' | 'isRestoring'
235235
}
236236

237237
type WithRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>

src/devtools/devtools.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React from 'react'
22
import { useSyncExternalStore } from 'use-sync-external-store/shim'
3-
import { notifyManager } from '../core'
43
import {
54
Query,
65
useQueryClient,
76
onlineManager,
7+
notifyManager,
88
QueryCache,
99
QueryClient,
1010
QueryKey as QueryKeyType,

src/devtools/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import { Query } from '../core'
2+
import type { Query } from 'react-query'
33

44
import { Theme, useTheme } from './theme'
55
import useMediaQuery from './useMediaQuery'

src/hydration/index.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/persistQueryClient/PersistQueryClientProvider.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22

33
import { persistQueryClient, PersistQueryClientOptions } from './persist'
44
import { QueryClientProvider, QueryClientProviderProps } from '../reactjs'
5-
import { IsHydratingProvider } from '../reactjs/Hydrate'
5+
import { IsRestoringProvider } from '../reactjs/isRestoring'
66

77
export type PersistQueryClientProviderProps = QueryClientProviderProps & {
88
persistOptions: Omit<PersistQueryClientOptions, 'queryClient'>
@@ -16,7 +16,7 @@ export const PersistQueryClientProvider = ({
1616
onSuccess,
1717
...props
1818
}: PersistQueryClientProviderProps): JSX.Element => {
19-
const [isHydrating, setIsHydrating] = React.useState(true)
19+
const [isRestoring, setIsRestoring] = React.useState(true)
2020
const refs = React.useRef({ persistOptions, onSuccess })
2121

2222
React.useEffect(() => {
@@ -25,7 +25,7 @@ export const PersistQueryClientProvider = ({
2525

2626
React.useEffect(() => {
2727
let isStale = false
28-
setIsHydrating(true)
28+
setIsRestoring(true)
2929
const [unsubscribe, promise] = persistQueryClient({
3030
...refs.current.persistOptions,
3131
queryClient: client,
@@ -34,7 +34,7 @@ export const PersistQueryClientProvider = ({
3434
promise.then(() => {
3535
if (!isStale) {
3636
refs.current.onSuccess?.()
37-
setIsHydrating(false)
37+
setIsRestoring(false)
3838
}
3939
})
4040

@@ -46,7 +46,7 @@ export const PersistQueryClientProvider = ({
4646

4747
return (
4848
<QueryClientProvider client={client} {...props}>
49-
<IsHydratingProvider value={isHydrating}>{children}</IsHydratingProvider>
49+
<IsRestoringProvider value={isRestoring}>{children}</IsRestoringProvider>
5050
</QueryClientProvider>
5151
)
5252
}

src/reactjs/Hydrate.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ import React from 'react'
33
import { hydrate, HydrateOptions } from '../core'
44
import { useQueryClient } from './QueryClientProvider'
55

6-
const IsHydratingContext = React.createContext(false)
7-
8-
export const useIsHydrating = () => React.useContext(IsHydratingContext)
9-
export const IsHydratingProvider = IsHydratingContext.Provider
10-
116
export function useHydrate(state: unknown, options: HydrateOptions = {}) {
127
const queryClient = useQueryClient({ context: options.context })
138

src/reactjs/QueryErrorResetBoundary.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export interface QueryErrorResetBoundaryProps {
4141
export const QueryErrorResetBoundary = ({
4242
children,
4343
}: QueryErrorResetBoundaryProps) => {
44-
const value = React.useMemo(() => createValue(), [])
44+
const [value] = React.useState(() => createValue())
4545
return (
4646
<QueryErrorResetBoundaryContext.Provider value={value}>
4747
{typeof children === 'function'

src/reactjs/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export { useMutation } from './useMutation'
1616
export { useQuery } from './useQuery'
1717
export { useQueries } from './useQueries'
1818
export { useInfiniteQuery } from './useInfiniteQuery'
19-
export { useHydrate, Hydrate, useIsHydrating } from './Hydrate'
19+
export { useHydrate, Hydrate } from './Hydrate'
20+
export { useIsRestoring } from './isRestoring'
2021

2122
// Types
2223
export * from './types'

src/reactjs/isRestoring.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react'
2+
3+
const IsRestoringContext = React.createContext(false)
4+
5+
export const useIsRestoring = () => React.useContext(IsRestoringContext)
6+
export const IsRestoringProvider = IsRestoringContext.Provider

src/reactjs/useBaseQuery.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'
66
import { useQueryClient } from './QueryClientProvider'
77
import { UseBaseQueryOptions } from './types'
88
import { shouldThrowError } from './utils'
9-
import { useIsHydrating } from './Hydrate'
9+
import { useIsRestoring } from './isRestoring'
1010

1111
export function useBaseQuery<
1212
TQueryFnData,
@@ -25,13 +25,13 @@ export function useBaseQuery<
2525
Observer: typeof QueryObserver
2626
) {
2727
const queryClient = useQueryClient({ context: options.context })
28-
const isHydrating = useIsHydrating()
28+
const isRestoring = useIsRestoring()
2929
const errorResetBoundary = useQueryErrorResetBoundary()
3030
const defaultedOptions = queryClient.defaultQueryOptions(options)
3131

3232
// Make sure results are optimistically set in fetching state before subscribing or updating options
33-
defaultedOptions._optimisticResults = isHydrating
34-
? 'isHydrating'
33+
defaultedOptions._optimisticResults = isRestoring
34+
? 'isRestoring'
3535
: 'optimistic'
3636

3737
// Include callbacks in batch renders
@@ -81,10 +81,10 @@ export function useBaseQuery<
8181
useSyncExternalStore(
8282
React.useCallback(
8383
onStoreChange =>
84-
isHydrating
84+
isRestoring
8585
? () => undefined
8686
: observer.subscribe(notifyManager.batchCalls(onStoreChange)),
87-
[observer, isHydrating]
87+
[observer, isRestoring]
8888
),
8989
() => observer.getCurrentResult(),
9090
() => observer.getCurrentResult()
@@ -105,7 +105,7 @@ export function useBaseQuery<
105105
defaultedOptions.suspense &&
106106
result.isLoading &&
107107
result.isFetching &&
108-
!isHydrating
108+
!isRestoring
109109
) {
110110
throw observer
111111
.fetchOptimistic(defaultedOptions)

src/reactjs/useQueries.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { notifyManager } from '../core/notifyManager'
66
import { QueriesObserver } from '../core/queriesObserver'
77
import { useQueryClient } from './QueryClientProvider'
88
import { UseQueryOptions, UseQueryResult } from './types'
9-
import { useIsHydrating } from './Hydrate'
9+
import { useIsRestoring } from './isRestoring'
1010

1111
// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.
1212
// - `context` is omitted as it is passed as a root-level option to `useQueries` instead.
@@ -144,21 +144,21 @@ export function useQueries<T extends any[]>({
144144
context?: UseQueryOptions['context']
145145
}): QueriesResults<T> {
146146
const queryClient = useQueryClient({ context })
147-
const isHydrating = useIsHydrating()
147+
const isRestoring = useIsRestoring()
148148

149149
const defaultedQueries = React.useMemo(
150150
() =>
151151
queries.map(options => {
152152
const defaultedOptions = queryClient.defaultQueryOptions(options)
153153

154154
// Make sure the results are already in fetching state before subscribing or updating options
155-
defaultedOptions._optimisticResults = isHydrating
156-
? 'isHydrating'
155+
defaultedOptions._optimisticResults = isRestoring
156+
? 'isRestoring'
157157
: 'optimistic'
158158

159159
return defaultedOptions
160160
}),
161-
[queries, queryClient, isHydrating]
161+
[queries, queryClient, isRestoring]
162162
)
163163

164164
const [observer] = React.useState(
@@ -170,10 +170,10 @@ export function useQueries<T extends any[]>({
170170
useSyncExternalStore(
171171
React.useCallback(
172172
onStoreChange =>
173-
isHydrating
173+
isRestoring
174174
? () => undefined
175175
: observer.subscribe(notifyManager.batchCalls(onStoreChange)),
176-
[observer, isHydrating]
176+
[observer, isRestoring]
177177
),
178178
() => observer.getCurrentResult(),
179179
() => observer.getCurrentResult()

0 commit comments

Comments
 (0)