T
TanStack•2y ago
like-gold

Persist data and network error

Hello guys, I wanted to use my custom asyncQueryClientPersister as a offline system for my mobile app. It seems to works, except that the first time the request fail, it will work and get last data fetched, but if I try again, it will then remove the stored data because last response is a network error and it seems to erase older data's. Is there a way to prevent this ? Or any other idea to make my app offline ? (I'm using Capacitor to run my JS website as a web app) Thanks
10 Replies
like-gold
like-goldOP•2y ago
Here is my react-query setup
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24,
},
},
})

export const QueryClientProvider = ({ children }: PropsWithChildren) => {
const { connect } = useAllQueries({
queryClient: queryClient,
query: {
username: "App",
userType: "User",
clientType: "client",
},
socketURL: "http://localhost:3030",
})

useEffect(() => {
connect()
}, [])

return (
<PersistQueryClientProvider client={queryClient} persistOptions={{ persister: dataStoragePersister }}>
{children}
</PersistQueryClientProvider>
)
}
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24,
},
},
})

export const QueryClientProvider = ({ children }: PropsWithChildren) => {
const { connect } = useAllQueries({
queryClient: queryClient,
query: {
username: "App",
userType: "User",
clientType: "client",
},
socketURL: "http://localhost:3030",
})

useEffect(() => {
connect()
}, [])

return (
<PersistQueryClientProvider client={queryClient} persistOptions={{ persister: dataStoragePersister }}>
{children}
</PersistQueryClientProvider>
)
}
And my component that makes a query
export default function UserProvider({}) {
const { data, error } = useQuery({
queryKey: ["user", "postLogin"],
queryFn: async () => (await axios.get(`${import.meta.env.VITE_API_URL}/auth/postLogin`)).data,
})

useEffect(() => {
console.log("UserProvider data: ", data)
console.log("UserProvider error: ", error)
}, [data, error])

return <React.Fragment />
}
export default function UserProvider({}) {
const { data, error } = useQuery({
queryKey: ["user", "postLogin"],
queryFn: async () => (await axios.get(`${import.meta.env.VITE_API_URL}/auth/postLogin`)).data,
})

useEffect(() => {
console.log("UserProvider data: ", data)
console.log("UserProvider error: ", error)
}, [data, error])

return <React.Fragment />
}
My UserProvider doesn't render anything, it is only here to fetch user data and fill them in a zustand store to unlock the app If I check my persister content, the queryKey just get erased when error occurs
sensitive-blue
sensitive-blue•17mo ago
we only persist queries that are in success state. If an error occurs, the query goes into error state. We don't persist errors because the Error class isn't serializable
like-gold
like-goldOP•17mo ago
Hey @TkDodo 🔮 , okay that lead me to an idea: Creating an axios response interceptor to check if the request error is a network error. My goal is to resolve() a Promise in this case, and in any other error I just reject() it with the given error. But react-query don't like to get an undefined successfull response. And since I don't have access to my queryClient to get the queryData and return it, I'm a bit lost on how to do. Do you think it could be a good idea ? And if yes, do you have any hint on how could I manage that ? Doesn't seems to have interceptor for react-query or any eventListener
sensitive-blue
sensitive-blue•17mo ago
you'd need to resolve with null
like-gold
like-goldOP•17mo ago
Hmm if I resolve with null it seems to empty my cache no ?
sensitive-blue
sensitive-blue•17mo ago
no, it will cache null just like it caches any other value
like-gold
like-goldOP•17mo ago
Hm okay well it's not what I needs then. I think I will subscribe my queryClient persister manually using persistClientQuery and export it globally to use it in my custom axios instance, that would allow me to resolve the cached getQueryData ! And i'll make a custom queryFn builder that will inject axios interceptors in it. I'm just not sure that it's a good practice to have a lot of axios instance
variable-lime
variable-lime•11mo ago
@TkDodo 🔮 We don't persist errors because the Error class isn't serializable This is understandable, but why is the persistor triggered to remove stale data for that key from storage while the in-memory cache client still has data available for that key?
sensitive-blue
sensitive-blue•11mo ago
not sure what you mean. it doesn't / shouldn't do that. The persisted state on disk is a 1:1 copy of what is in the cache.
variable-lime
variable-lime•11mo ago
@TkDodo 🔮 I have posted a separate question here. If you believe it shouldn't happen, I can try to reproduce it separately from the project to see if it's a bug.

Did you find this page helpful?