diff options
author | dan <dan.abramov@gmail.com> | 2024-04-04 02:51:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-04 02:51:10 +0100 |
commit | e51ccb46b8673b7444b7cac0792da4a9f6a91c4b (patch) | |
tree | f33935797d97837061cfa7dbb08c86d302571efb /src/lib/react-query.tsx | |
parent | db3cd3e8212bb497627e13aec6b5eac0ee05c0e3 (diff) | |
download | voidsky-e51ccb46b8673b7444b7cac0792da4a9f6a91c4b.tar.zst |
Scope query client per DID (#3333)
* Move QueryProvider inside the key * Pull useQueryClient-dependent code down in App.native * Remove useQueryClient dependency from session provider * Scope query client per DID
Diffstat (limited to 'src/lib/react-query.tsx')
-rw-r--r-- | src/lib/react-query.tsx | 92 |
1 files changed, 63 insertions, 29 deletions
diff --git a/src/lib/react-query.tsx b/src/lib/react-query.tsx index 08b61ee20..2fcd46942 100644 --- a/src/lib/react-query.tsx +++ b/src/lib/react-query.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, {useRef, useState} from 'react' import {AppState, AppStateStatus} from 'react-native' import AsyncStorage from '@react-native-async-storage/async-storage' import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' @@ -39,31 +39,27 @@ focusManager.setEventListener(onFocus => { } }) -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - // NOTE - // refetchOnWindowFocus breaks some UIs (like feeds) - // so we only selectively want to enable this - // -prf - refetchOnWindowFocus: false, - // Structural sharing between responses makes it impossible to rely on - // "first seen" timestamps on objects to determine if they're fresh. - // Disable this optimization so that we can rely on "first seen" timestamps. - structuralSharing: false, - // We don't want to retry queries by default, because in most cases we - // want to fail early and show a response to the user. There are - // exceptions, and those can be made on a per-query basis. For others, we - // should give users controls to retry. - retry: false, +const createQueryClient = () => + new QueryClient({ + defaultOptions: { + queries: { + // NOTE + // refetchOnWindowFocus breaks some UIs (like feeds) + // so we only selectively want to enable this + // -prf + refetchOnWindowFocus: false, + // Structural sharing between responses makes it impossible to rely on + // "first seen" timestamps on objects to determine if they're fresh. + // Disable this optimization so that we can rely on "first seen" timestamps. + structuralSharing: false, + // We don't want to retry queries by default, because in most cases we + // want to fail early and show a response to the user. There are + // exceptions, and those can be made on a per-query basis. For others, we + // should give users controls to retry. + retry: false, + }, }, - }, -}) - -const asyncStoragePersister = createAsyncStoragePersister({ - storage: AsyncStorage, - key: 'queryCache', -}) + }) const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] = { @@ -73,12 +69,50 @@ const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehyd }, } -const persistOptions = { - persister: asyncStoragePersister, - dehydrateOptions, +export function QueryProvider({ + children, + currentDid, +}: { + children: React.ReactNode + currentDid: string | undefined +}) { + return ( + <QueryProviderInner + // Enforce we never reuse cache between users. + // These two props MUST stay in sync. + key={currentDid} + currentDid={currentDid}> + {children} + </QueryProviderInner> + ) } -export function QueryProvider({children}: {children: React.ReactNode}) { +function QueryProviderInner({ + children, + currentDid, +}: { + children: React.ReactNode + currentDid: string | undefined +}) { + const initialDid = useRef(currentDid) + if (currentDid !== initialDid.current) { + throw Error( + 'Something is very wrong. Expected did to be stable due to key above.', + ) + } + // We create the query client here so that it's scoped to a specific DID. + // Do not move the query client creation outside of this component. + const [queryClient, _setQueryClient] = useState(() => createQueryClient()) + const [persistOptions, _setPersistOptions] = useState(() => { + const asyncPersister = createAsyncStoragePersister({ + storage: AsyncStorage, + key: 'queryClient-' + (currentDid ?? 'logged-out'), + }) + return { + persister: asyncPersister, + dehydrateOptions, + } + }) return ( <PersistQueryClientProvider client={queryClient} |