From 3f97df871fb99fca3de896daf5c671b15f770b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qu=E1=BB=91c=20Kh=C3=A1nh?= Date: Mon, 15 Jul 2024 17:37:52 +0700 Subject: [PATCH] feat(mobile): setup persistor for tanstack query (#127) --- apps/mobile/app/_layout.tsx | 38 +++++++++++++++++++++++-- apps/mobile/lib/client.ts | 9 +++++- apps/mobile/package.json | 3 ++ pnpm-lock.yaml | 55 +++++++++++++++++++++++++++++++++++-- 4 files changed, 98 insertions(+), 7 deletions(-) diff --git a/apps/mobile/app/_layout.tsx b/apps/mobile/app/_layout.tsx index fe91f032..7878bece 100644 --- a/apps/mobile/app/_layout.tsx +++ b/apps/mobile/app/_layout.tsx @@ -20,18 +20,41 @@ import { useColorScheme } from '@/hooks/useColorScheme' import { queryClient } from '@/lib/client' import { LocaleProvider } from '@/locales/provider' import { BottomSheetModalProvider } from '@gorhom/bottom-sheet' +import AsyncStorage from '@react-native-async-storage/async-storage' +import NetInfo from '@react-native-community/netinfo' import { DarkTheme, DefaultTheme, ThemeProvider, } from '@react-navigation/native' -import { QueryClientProvider } from '@tanstack/react-query' +import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' +import { focusManager, onlineManager } from '@tanstack/react-query' +import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client' import { LinearGradient } from 'expo-linear-gradient' import { cssInterop } from 'nativewind' +import { useEffect } from 'react' +import { AppState, type AppStateStatus, Platform } from 'react-native' import { GestureHandlerRootView } from 'react-native-gesture-handler' import { SafeAreaProvider } from 'react-native-safe-area-context' import { Svg } from 'react-native-svg' +// Online status management +onlineManager.setEventListener((setOnline) => { + return NetInfo.addEventListener((state) => { + setOnline(!!state.isConnected) + }) +}) + +function onAppStateChange(status: AppStateStatus) { + if (Platform.OS !== 'web') { + focusManager.setFocused(status === 'active') + } +} + +const asyncStoragePersister = createAsyncStoragePersister({ + storage: AsyncStorage, +}) + cssInterop(Svg, { className: { target: 'style', @@ -67,12 +90,21 @@ export default function RootLayout() { SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), }) + useEffect(() => { + const subscription = AppState.addEventListener('change', onAppStateChange) + + return () => subscription.remove() + }, []) + if (!fontsLoaded) { return null } return ( - + - + ) } diff --git a/apps/mobile/lib/client.ts b/apps/mobile/lib/client.ts index 350753b7..0b13be6a 100644 --- a/apps/mobile/lib/client.ts +++ b/apps/mobile/lib/client.ts @@ -19,4 +19,11 @@ export const getHonoClient = async () => { }) } -export const queryClient = new QueryClient() +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + networkMode: 'offlineFirst', + gcTime: 1000 * 60 * 60 * 24 * 7, // 1 week + }, + }, +}) diff --git a/apps/mobile/package.json b/apps/mobile/package.json index dfb0e2dc..d2c99d36 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -35,8 +35,11 @@ "@radix-ui/react-tabs": "^1.0.4", "@react-native-async-storage/async-storage": "^1.23.1", "@react-native-community/datetimepicker": "8.0.1", + "@react-native-community/netinfo": "11.3.1", "@react-navigation/native": "^6.0.2", + "@tanstack/query-async-storage-persister": "^5.51.1", "@tanstack/react-query": "^5.40.1", + "@tanstack/react-query-persist-client": "^5.51.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "date-fns": "^3.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3698c392..e1ed2401 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,7 +137,7 @@ importers: version: 4.11.1(react@18.3.1) '@lukemorales/query-key-factory': specifier: ^1.3.4 - version: 1.3.4(@tanstack/query-core@5.45.0)(@tanstack/react-query@5.45.1(react@18.3.1)) + version: 1.3.4(@tanstack/query-core@5.51.1)(@tanstack/react-query@5.45.1(react@18.3.1)) '@radix-ui/react-label': specifier: ^2.0.2 version: 2.0.2(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -153,12 +153,21 @@ importers: '@react-native-community/datetimepicker': specifier: 8.0.1 version: 8.0.1(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1))(react@18.3.1) + '@react-native-community/netinfo': + specifier: 11.3.1 + version: 11.3.1(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1)) '@react-navigation/native': specifier: ^6.0.2 version: 6.1.17(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1))(react@18.3.1) + '@tanstack/query-async-storage-persister': + specifier: ^5.51.1 + version: 5.51.1 '@tanstack/react-query': specifier: ^5.40.1 version: 5.45.1(react@18.3.1) + '@tanstack/react-query-persist-client': + specifier: ^5.51.1 + version: 5.51.1(@tanstack/react-query@5.45.1(react@18.3.1))(react@18.3.1) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -2080,6 +2089,11 @@ packages: react-native-windows: optional: true + '@react-native-community/netinfo@11.3.1': + resolution: {integrity: sha512-UBnJxyV0b7i9Moa97Av+HKho1ByzX0DtbJXzUQS5E3xhQs6P2D/Os0iw3ouy7joY1TVd6uIhplPbr7l1SJNaNQ==} + peerDependencies: + react-native: '>=0.59' + '@react-native/assets-registry@0.74.84': resolution: {integrity: sha512-dzUhwyaX04QosWZ8zyaaNB/WYZIdeDN1lcpfQbqiOhZJShRH+FLTDVONE/dqlMQrP+EO7lDqF0RrlIt9lnOCQQ==} engines: {node: '>=18'} @@ -2249,9 +2263,24 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@tanstack/query-async-storage-persister@5.51.1': + resolution: {integrity: sha512-DvJ1BovRJfpV1/OZn1IYeeS0c8H2vgK0vxmjhgzv2KrKeAd/rFx4hf8XAIty4ypgbgIMLnE5U3+nuI72ztTIvA==} + '@tanstack/query-core@5.45.0': resolution: {integrity: sha512-RVfIZQmFUTdjhSAAblvueimfngYyfN6HlwaJUPK71PKd7yi43Vs1S/rdimmZedPWX/WGppcq/U1HOj7O7FwYxw==} + '@tanstack/query-core@5.51.1': + resolution: {integrity: sha512-fJBMQMpo8/KSsWW5ratJR5+IFr7YNJ3K2kfP9l5XObYHsgfVy1w3FJUWU4FT2fj7+JMaEg33zOcNDBo0LMwHnw==} + + '@tanstack/query-persist-client-core@5.51.1': + resolution: {integrity: sha512-sEaZbqO5mdaJCymLAOUsf4DkVLSUcuKvhHC4pbL1Q/GbYs+r7vQkh2AeS5aRORyuhdL2jqOAs554ldee58e5sQ==} + + '@tanstack/react-query-persist-client@5.51.1': + resolution: {integrity: sha512-8sqMCsF6jpxdhuIQAt1z9PJjCPRlFuAFD/Tk5oXXWq5KjqVg/TP1XB/THtclw5KjNsGomkHSGPySNGY2zK1mJQ==} + peerDependencies: + '@tanstack/react-query': ^5.51.1 + react: ^18 || ^19 + '@tanstack/react-query@5.45.1': resolution: {integrity: sha512-mYYfJujKg2kxmkRRjA6nn4YKG3ITsKuH22f1kteJ5IuVQqgKUgbaSQfYwVP0gBS05mhwxO03HVpD0t7BMN7WOA==} peerDependencies: @@ -8547,9 +8576,9 @@ snapshots: '@lingui/core': 4.11.1 react: 18.3.1 - '@lukemorales/query-key-factory@1.3.4(@tanstack/query-core@5.45.0)(@tanstack/react-query@5.45.1(react@18.3.1))': + '@lukemorales/query-key-factory@1.3.4(@tanstack/query-core@5.51.1)(@tanstack/react-query@5.45.1(react@18.3.1))': dependencies: - '@tanstack/query-core': 5.45.0 + '@tanstack/query-core': 5.51.1 '@tanstack/react-query': 5.45.1(react@18.3.1) '@messageformat/parser@5.1.0': @@ -8977,6 +9006,10 @@ snapshots: react: 18.3.1 react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1) + '@react-native-community/netinfo@11.3.1(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1))': + dependencies: + react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.3.1) + '@react-native/assets-registry@0.74.84': {} '@react-native/babel-plugin-codegen@0.74.84(@babel/preset-env@7.24.7(@babel/core@7.24.7))': @@ -9264,8 +9297,24 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.6.3 + '@tanstack/query-async-storage-persister@5.51.1': + dependencies: + '@tanstack/query-persist-client-core': 5.51.1 + '@tanstack/query-core@5.45.0': {} + '@tanstack/query-core@5.51.1': {} + + '@tanstack/query-persist-client-core@5.51.1': + dependencies: + '@tanstack/query-core': 5.51.1 + + '@tanstack/react-query-persist-client@5.51.1(@tanstack/react-query@5.45.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/query-persist-client-core': 5.51.1 + '@tanstack/react-query': 5.45.1(react@18.3.1) + react: 18.3.1 + '@tanstack/react-query@5.45.1(react@18.3.1)': dependencies: '@tanstack/query-core': 5.45.0