I have a React 18 application and using React Query.
When I use queryClient.invalidateQueries({ queryKey: ['anecdotes'] });
after the PUT request that causes the change, the application makes a new GET request to retrieve the query data from the server. I am trying to avoid this extra HTTP GET request. So, I am trying to use queryClient.setQueryData
to make an update instead. How can I achieve this?
App.jsx
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { getAnecdotes, updateAnecdote } from './requests';
import AnecdoteForm from './components/AnecdoteForm';
import Notification from './components/Notification';
const App = () => {
const queryClient = useQueryClient();
const updateAnecdoteMutation = useMutation({
mutationFn: updateAnecdote,
onSuccess: () => {
// I am currently doing this; it causes an extra network request
queryClient.invalidateQueries({ queryKey: ['anecdotes'] });
// HOW DO I USE THE queryClient.setQueryData HERE?
// queryClient.setQueryData(['anecdotes']);
},
});
const result = useQuery({
queryKey: ['anecdotes'],
queryFn: getAnecdotes,
retry: false,
});
console.log(JSON.parse(JSON.stringify(result)));
if (result.isLoading) {
return <div>loading data...</div>;
}
if (result.isError) {
return <div>anecdote service not available due to problems in server</div>;
}
const anecdotes = result.data;
const handleVote = (anecdote) => {
console.log('vote', anecdote);
updateAnecdoteMutation.mutate({ ...anecdote, votes: anecdote.votes + 1 });
}
return (
<div>
<h3>Anecdote app</h3>
<Notification />
<AnecdoteForm />
{anecdotes.map(anecdote =>
<div key={anecdote.id}>
<div>
{anecdote.content}
</div>
<div>
has {anecdote.votes}
<button onClick={() => handleVote(anecdote)}>vote</button>
</div>
</div>
)}
</div>
);
}
export default App;
requests.js
file:
import axios from 'axios';
const baseUrl = 'http://localhost:3001/anecdotes';
export const getAnecdotes = () =>
axios.get(baseUrl).then(res => res.data);
export const createAnecdote = newAnecdote =>
axios.post(baseUrl, newAnecdote).then(res => res.data);
export const updateAnecdote = updatedAnecdote =>
axios.put(`${baseUrl}/${updatedAnecdote.id}`, updatedAnecdote).then(res => res.data);
2
Answers
Basically that would be something like this
Assuming you have same response from the mutation as for the get request (like get one entity / put one entity).
If you have get list of entities and want to update the list when you mutate only one entity – you need some extra logic to do a partial update based on some id.
Usually you’d want to use a key to distinguish requests and understand which ones you want to update and which ones you want to omit.
setQueryData
allows to directly access the current cached data through its updater function, so replace theanecdote
with the matching ID withupdatedAnecdote
. this way no extraget
call is made