React Query Adapter always bypasses clientLoader and hits the API #17
-
I'm trying to implement React Query Adapter with remix-client-cache, but for some reason, it is always hitting the server loader and bypassing the clientLoader. When I switch back to a manual cache, it works as expected. I didn't want to set a global staleTime, but instead do it on a per adapter-basis. So, I modified your example as such: export class ReactQueryAdapter implements CacheAdapter {
constructor(key: string, gcTime: number) {
queryClient.setQueryDefaults(key.split(','), {gcTime});
}
async getItem(key: string) {
return queryClient.getQueryData(key.split(','));
}
async removeItem(key: string) {
return queryClient.removeQueries({
queryKey: key.split(','),
});
}
async setItem(key: string, value: string) {
return queryClient.setQueryData(key.split(','), value);
}
} And then I use it like this: const {adapter} = createCacheAdapter(
() => new ReactQueryAdapter('search', 5000)
);
export const clientLoader = async (args: ClientLoaderFunctionArgs) => {
const {request} = args;
const url = new URL(request.url);
const query = url.searchParams.get('search') ?? '';
if (query.length < 3) {
return null;
}
return cacheClientLoader(args, {adapter, key: `search,${query}`});
};
clientLoader.hydrate = true; However, I've also tried doing the global way in the example and it still is hitting the server loader every time. I console logged the getItem function in the adapter class, and I can confirm that getItem is indeed returning the cached data, and the clientCacheLoader function is returning the expected data, but for some reason, the clientLoader still requests it from the server loader every time even though it's returning valid data. How do I resolve this? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Something to note, I am using this in a Remix API Route that I submit to from a fetcher.Form response. I'm not sure if this is why it isn't working. Maybe you must access the response via const fetcher = useFetcher();
const [search, setSearch] = useState('');
const results = fetcher.data;
useEffect(() => {
fetcher.submit(
{search: search.toLowerCase()},
{action: '/actions/search', method: 'GET'}
);
}, [search]);
return (
<fetcher.Form>
<input
name="search"
onChange={(event) => setSearch(event.target.value)}
placeholder="Search composites"
type="text"
value={search}
/>
</fetcher.Form>
); |
Beta Was this translation helpful? Give feedback.
-
Indeed, it seems that it's not compatible with Remix API Routes. I changed my clientLoader to manually set/get the RQ data and it started working. |
Beta Was this translation helpful? Give feedback.
-
I made a version that will work with API routes. export class ReactQueryCache {
constructor(key: string, gcTime: number) {
queryClient.setQueryDefaults(key.split(','), {gcTime});
}
getItem(key: string) {
const value = queryClient.getQueryData(key.split(','));
if (value) {
return JSON.parse(value as string);
}
return undefined;
}
async read(key: string, {serverLoader}: ClientLoaderFunctionArgs) {
if (this.getItem(key)) {
return this.getItem(key);
}
const data = await serverLoader();
this.setItem(key, data);
return data;
}
removeItem(key: string) {
return queryClient.removeQueries({
queryKey: key.split(','),
});
}
setItem(key: string, value: unknown) {
return queryClient.setQueryData(key.split(','), JSON.stringify(value));
}
} Usage const cache = new ReactQueryCache('search', 1000 * 60 * 10);
export const clientLoader = async (args: ClientLoaderFunctionArgs) => {
return cache.read('search,thing', args);
};
clientLoader.hydrate = true; |
Beta Was this translation helpful? Give feedback.
I made a version that will work with API routes.