Reputation: 5302
I'm just trying out react-query for the first time, and I've now ran into something I am getting pretty frustrated with.
Following code:
const userSettingsQueryClientKey = "userSettings_queryClient";
export const UserSettingsContextProvider: React.FC = ({ children }) => {
const queryClient = useQueryClient();
const { data } = useQuery(userSettingsQueryClientKey, async () => {
const request = new GetRequest<UserSettings>("/UserSettings/Get");
const result = await request.get();
return result.payload;
});
const { mutateAsync } = useMutation(async (settings: UserSettings) => {
const updateRequest = new VoidPostRequest<UserSettings>("/UserSettings/Update");
await updateRequest.post(settings);
return settings;
}, {
onSuccess: (newData) => {
queryClient.setQueryData(userSettingsQueryClientKey, newData);
}
})
return (
<UserSettingsContext.Provider value={{
settings: { ...data },
updateSettings: async (settings: UserSettings) => {
await mutateAsync(settings);
},
}}>
{children}
</UserSettingsContext.Provider>
);
}
I am having lots of problems getting the
queryClient.setQueryData(userSettingsQueryClientKey, newData);
part to work.
I have properly debugged my code several times now. During the flow of my app:
The settings are initialized to { useOldVersion: true }
At some point in time, a user will click a checkbox, and call updateSettings
with { useOldVersion: false }
The mutation properly posts this update to the server
The onSuccess is called, properly setting the query state to the new value.
However, after the onSuccess
the const { data }
I'm getting from my useQuery
call still delivers the old, stale data. I verified all the previous steps with the debugger, and now I'm really not sure where I'm going wrong.
Any advice how to properly get the new state from the useQuery
call?
Upvotes: 0
Views: 2570
Reputation: 5302
I just found my very stupid bug. All the answers were helpful, but could never find the problem.
My app looked like this:
export default function App() {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<div className="App">
<h1>Hello CodeSandbox</h1>
<MyComponent />
<h2>Start editing to see some magic happen!</h2>
</div>
</QueryClientProvider>
);
}
This meant that the query client is constantly regenerated.
It works when it's moved out like this, so the value is persisted:
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<div className="App">
<h1>Hello CodeSandbox</h1>
<MyComponent />
<h2>Start editing to see some magic happen!</h2>
</div>
</QueryClientProvider>
);
}
Upvotes: 4
Reputation: 4741
The recommended way to notify the query has changed is through the use of queryClient.invalidateQueries
.
You can see an example in the RQ docs.
const { mutateAsync } = useMutation(
async (settings: UserSettings) => {
const updateRequest = new VoidPostRequest<UserSettings>("/UserSettings/Update");
await updateRequest.post(settings);
return settings;
},
{
onSuccess: (newData) => {
queryClient.setQueryData(userSettingsQueryClientKey, newData);
queryClient.invalidateQueries(userSettingsQueryClientKey);
}
}
);
Upvotes: -1
Reputation: 1167
You can try using refetchQueries method exposed by QueryClient. Your code would look something like:
const { mutateAsync } = useMutation(async (settings: UserSettings) => {
const updateRequest = new VoidPostRequest<UserSettings>("/UserSettings/Update");
await updateRequest.post(settings);
return settings;
}, {
onSuccess: (newData) => {
queryClient.setQueryData(userSettingsQueryClientKey, newData);
queryClient.refetchQueries(userSettingsQueryClientKey);// this is new
}
})
Upvotes: 0