Scope query client per DID
This commit is contained in:
+1
-1
@@ -75,7 +75,7 @@ function InnerApp() {
|
|||||||
<React.Fragment
|
<React.Fragment
|
||||||
// Resets the entire tree below when it changes:
|
// Resets the entire tree below when it changes:
|
||||||
key={currentAccount?.did}>
|
key={currentAccount?.did}>
|
||||||
<QueryProvider>
|
<QueryProvider currentDid={currentAccount?.did}>
|
||||||
<PushNotificationsListener>
|
<PushNotificationsListener>
|
||||||
<StatsigProvider>
|
<StatsigProvider>
|
||||||
<LabelDefsProvider>
|
<LabelDefsProvider>
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ function InnerApp() {
|
|||||||
<React.Fragment
|
<React.Fragment
|
||||||
// Resets the entire tree below when it changes:
|
// Resets the entire tree below when it changes:
|
||||||
key={currentAccount?.did}>
|
key={currentAccount?.did}>
|
||||||
<QueryProvider>
|
<QueryProvider currentDid={currentAccount?.did}>
|
||||||
<StatsigProvider>
|
<StatsigProvider>
|
||||||
<LabelDefsProvider>
|
<LabelDefsProvider>
|
||||||
<LoggedOutViewProvider>
|
<LoggedOutViewProvider>
|
||||||
|
|||||||
+63
-29
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, {useRef, useState} from 'react'
|
||||||
import {AppState, AppStateStatus} from 'react-native'
|
import {AppState, AppStateStatus} from 'react-native'
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
||||||
@@ -39,31 +39,27 @@ focusManager.setEventListener(onFocus => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const createQueryClient = () =>
|
||||||
defaultOptions: {
|
new QueryClient({
|
||||||
queries: {
|
defaultOptions: {
|
||||||
// NOTE
|
queries: {
|
||||||
// refetchOnWindowFocus breaks some UIs (like feeds)
|
// NOTE
|
||||||
// so we only selectively want to enable this
|
// refetchOnWindowFocus breaks some UIs (like feeds)
|
||||||
// -prf
|
// so we only selectively want to enable this
|
||||||
refetchOnWindowFocus: false,
|
// -prf
|
||||||
// Structural sharing between responses makes it impossible to rely on
|
refetchOnWindowFocus: false,
|
||||||
// "first seen" timestamps on objects to determine if they're fresh.
|
// Structural sharing between responses makes it impossible to rely on
|
||||||
// Disable this optimization so that we can rely on "first seen" timestamps.
|
// "first seen" timestamps on objects to determine if they're fresh.
|
||||||
structuralSharing: false,
|
// Disable this optimization so that we can rely on "first seen" timestamps.
|
||||||
// We don't want to retry queries by default, because in most cases we
|
structuralSharing: false,
|
||||||
// want to fail early and show a response to the user. There are
|
// We don't want to retry queries by default, because in most cases we
|
||||||
// exceptions, and those can be made on a per-query basis. For others, we
|
// want to fail early and show a response to the user. There are
|
||||||
// should give users controls to retry.
|
// exceptions, and those can be made on a per-query basis. For others, we
|
||||||
retry: false,
|
// should give users controls to retry.
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
|
|
||||||
const asyncStoragePersister = createAsyncStoragePersister({
|
|
||||||
storage: AsyncStorage,
|
|
||||||
key: 'queryCache',
|
|
||||||
})
|
|
||||||
|
|
||||||
const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] =
|
const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] =
|
||||||
{
|
{
|
||||||
@@ -73,12 +69,50 @@ const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehyd
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const persistOptions = {
|
export function QueryProvider({
|
||||||
persister: asyncStoragePersister,
|
children,
|
||||||
dehydrateOptions,
|
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 (
|
return (
|
||||||
<PersistQueryClientProvider
|
<PersistQueryClientProvider
|
||||||
client={queryClient}
|
client={queryClient}
|
||||||
|
|||||||
Reference in New Issue
Block a user