Replace queryClient
This commit is contained in:
+15
-13
@@ -12,7 +12,7 @@ import {
|
||||
import * as SplashScreen from 'expo-splash-screen'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||
import {init as initPersistedState} from '#/state/persisted'
|
||||
@@ -20,11 +20,7 @@ import * as persisted from '#/state/persisted'
|
||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||
import * as notifications from 'lib/notifications/notifications'
|
||||
import {
|
||||
asyncStoragePersister,
|
||||
dehydrateOptions,
|
||||
queryClient,
|
||||
} from 'lib/react-query'
|
||||
import {GlobalQueryClientProvider} from 'lib/react-query'
|
||||
import {s} from 'lib/styles'
|
||||
import {ThemeProvider} from 'lib/ThemeContext'
|
||||
import {Provider as DialogStateProvider} from 'state/dialogs'
|
||||
@@ -55,22 +51,30 @@ import {listenSessionDropped} from './state/events'
|
||||
SplashScreen.preventAutoHideAsync()
|
||||
|
||||
function InnerApp() {
|
||||
const queryClient = useQueryClient()
|
||||
const {isInitialLoad, currentAccount} = useSession()
|
||||
const {resumeSession} = useSessionApi()
|
||||
const theme = useColorModeTheme()
|
||||
const {_} = useLingui()
|
||||
useIntentHandler()
|
||||
|
||||
// init
|
||||
useEffect(() => {
|
||||
notifications.init(queryClient)
|
||||
listenSessionDropped(() => {
|
||||
}, [queryClient])
|
||||
|
||||
useEffect(() => {
|
||||
return listenSessionDropped(() => {
|
||||
Toast.show(_(msg`Sorry! Your session expired. Please log in again.`))
|
||||
})
|
||||
}, [_])
|
||||
|
||||
// init
|
||||
useEffect(() => {
|
||||
const account = persisted.get('session').currentAccount
|
||||
resumeSession(account)
|
||||
}, [resumeSession, _])
|
||||
// TODO test
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
|
||||
@@ -121,9 +125,7 @@ function App() {
|
||||
* that is set up in the InnerApp component above.
|
||||
*/
|
||||
return (
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{persister: asyncStoragePersister, dehydrateOptions}}>
|
||||
<GlobalQueryClientProvider>
|
||||
<SessionProvider>
|
||||
<ShellStateProvider>
|
||||
<PrefsStateProvider>
|
||||
@@ -145,7 +147,7 @@ function App() {
|
||||
</PrefsStateProvider>
|
||||
</ShellStateProvider>
|
||||
</SessionProvider>
|
||||
</PersistQueryClientProvider>
|
||||
</GlobalQueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+29
-35
@@ -1,44 +1,38 @@
|
||||
import 'lib/sentry' // must be near top
|
||||
|
||||
import React, {useState, useEffect} from 'react'
|
||||
import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client'
|
||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||
import {RootSiblingParent} from 'react-native-root-siblings'
|
||||
|
||||
import 'view/icons'
|
||||
|
||||
import {ThemeProvider as Alf} from '#/alf'
|
||||
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {RootSiblingParent} from 'react-native-root-siblings'
|
||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||
|
||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||
import {init as initPersistedState} from '#/state/persisted'
|
||||
import {Shell} from 'view/shell/index'
|
||||
import {ToastContainer} from 'view/com/util/Toast.web'
|
||||
import {ThemeProvider} from 'lib/ThemeContext'
|
||||
import {
|
||||
queryClient,
|
||||
asyncStoragePersister,
|
||||
dehydrateOptions,
|
||||
} from 'lib/react-query'
|
||||
import {Provider as ShellStateProvider} from 'state/shell'
|
||||
import {Provider as ModalStateProvider} from 'state/modals'
|
||||
import {Provider as DialogStateProvider} from 'state/dialogs'
|
||||
import {Provider as LightboxStateProvider} from 'state/lightbox'
|
||||
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
||||
import {Provider as InvitesStateProvider} from 'state/invites'
|
||||
import {Provider as PrefsStateProvider} from 'state/preferences'
|
||||
import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out'
|
||||
import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed'
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||
import I18nProvider from './locale/i18nProvider'
|
||||
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||
import {GlobalQueryClientProvider} from 'lib/react-query'
|
||||
import {ThemeProvider} from 'lib/ThemeContext'
|
||||
import {Provider as DialogStateProvider} from 'state/dialogs'
|
||||
import {Provider as InvitesStateProvider} from 'state/invites'
|
||||
import {Provider as LightboxStateProvider} from 'state/lightbox'
|
||||
import {Provider as ModalStateProvider} from 'state/modals'
|
||||
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
||||
import {Provider as PrefsStateProvider} from 'state/preferences'
|
||||
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
||||
import {
|
||||
Provider as SessionProvider,
|
||||
useSession,
|
||||
useSessionApi,
|
||||
} from 'state/session'
|
||||
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {Provider as ShellStateProvider} from 'state/shell'
|
||||
import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out'
|
||||
import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed'
|
||||
import {ToastContainer} from 'view/com/util/Toast.web'
|
||||
import {Shell} from 'view/shell/index'
|
||||
import {ThemeProvider as Alf} from '#/alf'
|
||||
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
||||
import {Provider as PortalProvider} from '#/components/Portal'
|
||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||
import I18nProvider from './locale/i18nProvider'
|
||||
|
||||
function InnerApp() {
|
||||
const {isInitialLoad, currentAccount} = useSession()
|
||||
@@ -50,7 +44,9 @@ function InnerApp() {
|
||||
useEffect(() => {
|
||||
const account = persisted.get('session').currentAccount
|
||||
resumeSession(account)
|
||||
}, [resumeSession])
|
||||
// only run this effect once on first load TODO test
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
// wait for session to resume
|
||||
if (isInitialLoad) return null
|
||||
@@ -100,9 +96,7 @@ function App() {
|
||||
* that is set up in the InnerApp component above.
|
||||
*/
|
||||
return (
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{persister: asyncStoragePersister, dehydrateOptions}}>
|
||||
<GlobalQueryClientProvider>
|
||||
<SessionProvider>
|
||||
<ShellStateProvider>
|
||||
<PrefsStateProvider>
|
||||
@@ -124,7 +118,7 @@ function App() {
|
||||
</PrefsStateProvider>
|
||||
</ShellStateProvider>
|
||||
</SessionProvider>
|
||||
</PersistQueryClientProvider>
|
||||
</GlobalQueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import React from 'react'
|
||||
import {AppState, AppStateStatus} from 'react-native'
|
||||
import {QueryClient, focusManager} from '@tanstack/react-query'
|
||||
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import {PersistQueryClientProviderProps} from '@tanstack/react-query-persist-client'
|
||||
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
||||
import {focusManager, QueryClient} from '@tanstack/react-query'
|
||||
import {
|
||||
PersistQueryClientProvider,
|
||||
PersistQueryClientProviderProps,
|
||||
} from '@tanstack/react-query-persist-client'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {isNative} from '#/platform/detection'
|
||||
|
||||
// any query keys in this array will be persisted to AsyncStorage
|
||||
@@ -35,6 +40,19 @@ focusManager.setEventListener(onFocus => {
|
||||
}
|
||||
})
|
||||
|
||||
export const asyncStoragePersister = createAsyncStoragePersister({
|
||||
storage: AsyncStorage,
|
||||
key: 'queryCache',
|
||||
})
|
||||
|
||||
export const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] =
|
||||
{
|
||||
shouldDehydrateMutation: (_: any) => false,
|
||||
shouldDehydrateQuery: query => {
|
||||
return STORED_CACHE_QUERY_KEYS.includes(String(query.queryKey[0]))
|
||||
},
|
||||
}
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
@@ -56,15 +74,73 @@ export const queryClient = new QueryClient({
|
||||
},
|
||||
})
|
||||
|
||||
export const asyncStoragePersister = createAsyncStoragePersister({
|
||||
storage: AsyncStorage,
|
||||
key: 'queryCache',
|
||||
function createGlobalQueryClient() {
|
||||
return 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,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
let __globalQueryClient = createGlobalQueryClient()
|
||||
|
||||
export function getGlobalQueryClient() {
|
||||
return __globalQueryClient
|
||||
}
|
||||
|
||||
type Context = {
|
||||
resetGlobalQueryClient(): void
|
||||
}
|
||||
|
||||
const Context = React.createContext<Context>({
|
||||
resetGlobalQueryClient() {},
|
||||
})
|
||||
|
||||
export const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] =
|
||||
{
|
||||
shouldDehydrateMutation: (_: any) => false,
|
||||
shouldDehydrateQuery: query => {
|
||||
return STORED_CACHE_QUERY_KEYS.includes(String(query.queryKey[0]))
|
||||
},
|
||||
}
|
||||
export function useResetGlobalQueryClient() {
|
||||
return React.useContext(Context).resetGlobalQueryClient
|
||||
}
|
||||
|
||||
export function GlobalQueryClientProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const [queryClient, setQueryClient] = React.useState(() =>
|
||||
createGlobalQueryClient(),
|
||||
)
|
||||
const context = React.useMemo<Context>(() => {
|
||||
return {
|
||||
resetGlobalQueryClient() {
|
||||
logger.debug(`react query: setting new global query client`)
|
||||
const client = createGlobalQueryClient()
|
||||
__globalQueryClient = client
|
||||
setQueryClient(client)
|
||||
},
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Context.Provider value={context}>
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{persister: asyncStoragePersister, dehydrateOptions}}>
|
||||
{children}
|
||||
</PersistQueryClientProvider>
|
||||
</Context.Provider>
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import {jwtDecode} from 'jwt-decode'
|
||||
import {track} from '#/lib/analytics/analytics'
|
||||
import {networkRetry} from '#/lib/async/retry'
|
||||
import {IS_TEST_USER} from '#/lib/constants'
|
||||
import {useResetGlobalQueryClient} from '#/lib/react-query'
|
||||
import {logEvent, LogEvents} from '#/lib/statsig/statsig'
|
||||
import {hasProp} from '#/lib/type-guards'
|
||||
import {logger} from '#/logger'
|
||||
@@ -179,6 +180,7 @@ function createPersistSessionHandler(
|
||||
|
||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
const queryClient = useQueryClient()
|
||||
const resetGlobalQueryClient = useResetGlobalQueryClient()
|
||||
const isDirty = React.useRef(false)
|
||||
const [state, setState] = React.useState<SessionState>({
|
||||
isInitialLoad: true,
|
||||
@@ -373,6 +375,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
persistSession: createPersistSessionHandler(
|
||||
account,
|
||||
({expired, refreshedAccount}) => {
|
||||
console.log('RESUME: PERSIST')
|
||||
upsertAccount(refreshedAccount, expired)
|
||||
},
|
||||
{networkErrorCallback: clearCurrentAccount},
|
||||
@@ -414,8 +417,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
* state so that the app can rerender with new data.
|
||||
*/
|
||||
agent.session = prevSession
|
||||
resetGlobalQueryClient()
|
||||
__globalAgent = agent
|
||||
queryClient.clear()
|
||||
upsertAccount(account)
|
||||
|
||||
if (prevSession.deactivated) {
|
||||
@@ -444,6 +447,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
try {
|
||||
// this calls `upsertAccount` via `agent.resumeSession` and persistor
|
||||
await resumeSessionWithFreshAccount()
|
||||
console.log('RESUME: DONE')
|
||||
resetGlobalQueryClient()
|
||||
// only update global agen if resumeSessionWithFreshAccount succeeded
|
||||
__globalAgent = agent
|
||||
} catch (e) {
|
||||
@@ -456,7 +461,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
})
|
||||
|
||||
__globalAgent = PUBLIC_BSKY_AGENT
|
||||
} finally {
|
||||
queryClient.clear()
|
||||
}
|
||||
}
|
||||
@@ -487,7 +491,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
}
|
||||
}
|
||||
},
|
||||
[upsertAccount, queryClient, clearCurrentAccount],
|
||||
[upsertAccount, queryClient, clearCurrentAccount, resetGlobalQueryClient],
|
||||
)
|
||||
|
||||
const resumeSession = React.useCallback<ApiContext['resumeSession']>(
|
||||
|
||||
Reference in New Issue
Block a user