Reputation: 10772
I am using react query to fetch a list of items. After creating a new item, I am calling refetch
on my query to get the updated list. I see a new api call is made, and the new item I just created is returned as part of the api response. However, react-query is not updating its data value.
My code has a useQuery
wrapped in a hook to be able to be used in multiple places, as the query fn and its dependencies are complex:
// simplified version of the useQuery:
export const useItemsQuery = (search = "") => {
const { user } = usePermissions();
const filter = useStore((state) => state.projects.filter);
const projects = useQuery({
queryKey: [
"Items list",
`Items by ${filter}`,
`User: ${user.id}`
],
queryFn: () => complexQueryFunction(filter, user.id)
});
return projects;
};
In a few other components
// Component 1
const items = useItemsQuery()
items.data.map(...etc)
// Component 2
const items = useItemsQuery()
items.data.find(...etc)
The most confounding this is that even if I do into my react-query devtools and manually click "invalidate", the api call is made, and a new list is fetched. I can see that the data in the api call does not match the data in the react query devtools:
In the api call, 10 items:
In the react query devtools, where I clicked "invalidate" that caused the above api call, 9 items:
I find it bizarre that not only calling refetch
or queryClient.invalidateQuery({queryKey: [<the query key>]})
calls the api correctly and gets new data, but using the actual react-query devtools calls the api and gets the new data, but the data in reat-query's cache is not updated.
What might be causing this? Someone mentioned in another question that if you had mutated the data directly in place, react-query will not work properly and not update the cache. I checked my code and I don't believe this is the case. What else might be causing react-query to not update its .data
to the value coming from the network call?
Upvotes: 5
Views: 1773
Reputation: 2169
Problems like this are tricky and can have multiple causes:
If items.data
is mutated directly, React Query won’t update. Try freezing it to catch any unwanted mutations:
useEffect(() => {
if (items.data) Object.freeze(items.data);
}, [items.data]);
If user.id
or filter
changes unexpectedly, cache behavior can break - log it:
console.debug("Query Key:", ["Items list", `Items by ${filter}`, `User: ${user.id}`]);
If the API returns the same object reference, React Query won’t register a change. Force a shallow copy:
const projects = useQuery({
queryKey: ["Items list", `Items by ${filter}`, `User: ${user.id}`],
queryFn: () => complexQueryFunction(filter, user.id),
select: (data) => [...data],
});
Log the result of refetch()
:
const { refetch } = useItemsQuery();
useEffect(() => {
refetch().then(({ data }) => console.log("Refetch result:", data));
}, []);
set staleTime: 0
and gcTime: 0
to evict cache before refetch:
const projects = useQuery({
queryKey: ["Items list", `Items by ${filter}`, `User: ${user.id}`],
queryFn: () => complexQueryFunction(filter, user.id),
staleTime: 0,
gcTime: 0,
});
If you're using a mutation, manually invalidate the query:
const mutation = useMutation(createNewItem, {
onSuccess: () => {
queryClient.invalidateQueries(["Items list"]);
},
});
... or optimistically update:
onSuccess: (newItem) => {
queryClient.setQueryData(["Items list"], (oldData) => [...oldData, newItem]);
}
log the actual data instead of trusting devtools:
useEffect(() => {
console.log("Current Query Data:", items.data);
}, [items.data]);
if refetch logs the correct data but the UI doesn’t update, it's likely a stale cache issue.
useMemo
or useCallback
or React.memo
to see if it then updates as expecteduseStore
might use a shallow comparison ((state) => state.items), React might not detect updateitems.data
// log renderings to ensure your state updates are being picked up
useEffect(() => {
console.log("Items Data Updated:", items.data);
}, [items.data]);
Upvotes: 0