diff --git a/package.json b/package.json index 5c31f10f05..14b1e2f908 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,9 @@ "@segment/sovran-react-native": "^0.4.5", "@sentry/react-native": "5.5.0", "@tamagui/focus-scope": "^1.84.1", + "@tanstack/query-async-storage-persister": "^5.25.0", "@tanstack/react-query": "^5.8.1", + "@tanstack/react-query-persist-client": "^5.25.0", "@tiptap/core": "^2.0.0-beta.220", "@tiptap/extension-document": "^2.0.0-beta.220", "@tiptap/extension-hard-break": "^2.0.3", diff --git a/src/App.native.tsx b/src/App.native.tsx index 1284154f3b..c79088cebd 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -5,7 +5,7 @@ import React, {useState, useEffect} from 'react' import {RootSiblingParent} from 'react-native-root-siblings' import * as SplashScreen from 'expo-splash-screen' import {GestureHandlerRootView} from 'react-native-gesture-handler' -import {QueryClientProvider} from '@tanstack/react-query' +import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client' import { SafeAreaProvider, initialWindowMetrics, @@ -22,7 +22,11 @@ import {s} from 'lib/styles' import {Shell} from 'view/shell' import * as notifications from 'lib/notifications/notifications' import * as Toast from 'view/com/util/Toast' -import {queryClient} from 'lib/react-query' +import { + queryClient, + asyncStoragePersister, + dehydrateOptions, +} from 'lib/react-query' import {TestCtrls} from 'view/com/testing/TestCtrls' import {Provider as ShellStateProvider} from 'state/shell' import {Provider as ModalStateProvider} from 'state/modals' @@ -110,7 +114,9 @@ function App() { * that is set up in the InnerApp component above. */ return ( - + @@ -132,7 +138,7 @@ function App() { - + ) } diff --git a/src/App.web.tsx b/src/App.web.tsx index f10bb194d4..e2f1f07ff4 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -1,7 +1,7 @@ import 'lib/sentry' // must be near top import React, {useState, useEffect} from 'react' -import {QueryClientProvider} from '@tanstack/react-query' +import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client' import {SafeAreaProvider} from 'react-native-safe-area-context' import {RootSiblingParent} from 'react-native-root-siblings' @@ -13,7 +13,11 @@ 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} from 'lib/react-query' +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' @@ -88,7 +92,9 @@ function App() { * that is set up in the InnerApp component above. */ return ( - + @@ -110,7 +116,7 @@ function App() { - + ) } diff --git a/src/lib/react-query.ts b/src/lib/react-query.ts index 7fe3fe7a47..3250f865ea 100644 --- a/src/lib/react-query.ts +++ b/src/lib/react-query.ts @@ -1,6 +1,11 @@ import {AppState, AppStateStatus} from 'react-native' -import {QueryClient, focusManager} from '@tanstack/react-query' +import {QueryClient, focusManager, Query} from '@tanstack/react-query' import {isNative} from '#/platform/detection' +import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' +import AsyncStorage from '@react-native-async-storage/async-storage' + +// any query keys in this array will be persisted to AsyncStorage +const STORED_CACHE_QUERY_KEYS = ['labelers-detailed-info'] focusManager.setEventListener(onFocus => { if (isNative) { @@ -48,3 +53,17 @@ export const queryClient = new QueryClient({ }, }, }) + +export const asyncStoragePersister = createAsyncStoragePersister({ + storage: AsyncStorage, + key: 'queryCache', +}) + +export const dehydrateOptions = { + shouldDehydrateMutation: (_: any) => false, + shouldDehydrateQuery: (query: any) => { + // something is wrong with useQuery's exported types, so we have to coerce here + const q = query as Query + return STORED_CACHE_QUERY_KEYS.includes(String(q.queryKey[0])) + }, +} diff --git a/src/state/queries/labeler.ts b/src/state/queries/labeler.ts index 22e9f9a90a..06edd8b158 100644 --- a/src/state/queries/labeler.ts +++ b/src/state/queries/labeler.ts @@ -6,7 +6,10 @@ import {getAgent} from '#/state/session' import {preferencesQueryKey} from '#/state/queries/preferences' export const labelerInfoQueryKey = (did: string) => ['labeler-info', did] -export const labelersInfoQueryKey = (dids: string[]) => ['labelers-info', dids] +export const labelersInfoQueryKey = (dids: string[]) => [ + 'labelers-info', + dids.sort(), +] export const labelersDetailedInfoQueryKey = (dids: string[]) => [ 'labelers-detailed-info', dids, @@ -47,6 +50,7 @@ export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) { return useQuery({ enabled: !!dids.length, queryKey: labelersDetailedInfoQueryKey(dids), + gcTime: 1000 * 60 * 60 * 6, // 6 hours queryFn: async () => { const res = await getAgent().app.bsky.labeler.getServices({ dids, diff --git a/yarn.lock b/yarn.lock index a85ea79b8c..14fd49c477 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7057,11 +7057,37 @@ dependencies: "@tamagui/constants" "1.84.1" +"@tanstack/query-async-storage-persister@^5.25.0": + version "5.25.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.25.0.tgz#0e8a2a781b8e32a81a5d02a688d6fcdfd055235b" + integrity sha512-58UTp1CuLr2mehsJRMOd8IZPtYGHFeL+uHnHyRd1kmbwo7wDaa8HXstiBdTRq5KokxIXy9FiFbA06LtKuOiwMQ== + dependencies: + "@tanstack/query-persist-client-core" "5.25.0" + +"@tanstack/query-core@5.25.0": + version "5.25.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.25.0.tgz#e08ed0a9fad34c8005d1a282e57280031ac50cdc" + integrity sha512-vlobHP64HTuSE68lWF1mEhwSRC5Q7gaT+a/m9S+ItuN+ruSOxe1rFnR9j0ACWQ314BPhBEVKfBQ6mHL0OWfdbQ== + "@tanstack/query-core@5.8.1": version "5.8.1" resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.8.1.tgz#5215a028370d9b2f32e83787a0ea119e2f977996" integrity sha512-Y0enatz2zQXBAsd7XmajlCs+WaitdR7dIFkqz9Xd7HL4KV04JOigWVreYseTmNH7YFSBSC/BJ9uuNp1MAf+GfA== +"@tanstack/query-persist-client-core@5.25.0": + version "5.25.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-persist-client-core/-/query-persist-client-core-5.25.0.tgz#52fa634a8067d7b965854a532a33077fd4df0eff" + integrity sha512-sEUsEZ/XWkOosO45CDBI5nj5woCS+DUd9Dk8pGpU8MkeH0EVd3p4N5CdbjNhrreyy5Krf3rpNaiRN9ygLX/rWA== + dependencies: + "@tanstack/query-core" "5.25.0" + +"@tanstack/react-query-persist-client@^5.25.0": + version "5.25.0" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-5.25.0.tgz#ecbd1362cd6fd94e723d54f5af477d0812852dab" + integrity sha512-j1+GyFj4UQGWuiFZoDUVJZS+wxqKd9SGvPlyHG619zzYNN+QQu4B5uvvHc6U8MroM377EOBOuLKK3W6qsAdahQ== + dependencies: + "@tanstack/query-persist-client-core" "5.25.0" + "@tanstack/react-query@^5.8.1": version "5.8.1" resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.8.1.tgz#22a122016e23a39acd90341954a895980ec21ade"