I recently started using React Query to manage my data fetching and caching, but I'm having trouble figuring out how to update displayed data without constantly sending mutations.
For example, let's say I have a query at the top of my component to get a User, and then I display all the users in simple cards. Normally, if I want to update the displayed user's firstname, I would bind a function like handleFieldChange(id_user, field, value) to the input. This function would simply update the state of the given user, and then if I hit the save button, it would send the updated user to the server.
Here's some code that illustrates this approach (code blocks are just exemples):
// react
import { useState, useEffect } from 'react';
// api
import { getUsers, updateUser } from '../api/users';
const UserCardGrid: React.FC = () => {
const [users, setUsers] = useState([]);
// handlers
const handleGetUsers = async () => {
const { data } = await getUsers();
setUsers(data);
};
const handleFieldChange = (id_user: number, key: string, value: any) => {
const newUsers = users.map((user: any) => {
if (user.id_user === id_user) {
return {
...user,
[key]: value,
};
}
return user;
});
setUsers(newUsers);
};
const handleUpdateUser = async (id_user: number) => {
const user = users.find((user: any) => user.id_user === id_user);
await updateUser(id_user, user);
};
// effects
useEffect(() => {
handleGetUsers();
}, []);
return (
<div className='grid'>
{users.map((user: any) => (
<div key={user.id_user}>
<input
key={user.id_user}
type='text'
value={user.username}
onChange={(e) =>
handleFieldChange(user.id_user, 'username',e.target.value)
}
/>
<button onClick={() => handleUpdateUser(user.id_user)}>Update</button>
</div>
))}
</div>
);
};
export default UserCardGrid;
However, with React Query, I can't do that. If I want to update the displayed text, I need to update the cache or send a useMutation query every time I type something. I know I can use useMutation and optimistic updates, but it seems wrong to send a mutation every time the user types something (even if i use a debounce mecanism).
// api
import { useQuery, useMutation } from '@tanstack/react-query';
import { getUsers, updateUser } from '../api/users';
const UserCardGrid: React.FC = () => {
const usersQ = useQuery(['users'], getUsers);
const userM = useMutation(updateUser);
// handlers
const handleFieldChange = (id_user: number, key: string, value: any) => {
// HOW COULD I IMPLEMENT THIS?
};
const handleUpdateUser = async (id_user: number) => {
userM.mutate(id_user, usersQ.data.find((user: any) => user.id_user === id_user));
};
return (
<div className='grid'>
{usersQ.data?.map((user: any) => (
<div key={user.id_user}>
<input
key={user.id_user}
type='text'
value={user.username}
onChange={(e) =>
handleFieldChange(user.id_user, 'username',e.target.value)
}
/>
<button onClick={() => handleUpdateUser(user.id_user)}>Update</button>
</div>
))}
</div>
);
};
export default UserCardGrid;
I just want to be able to update my user how I want, and update it when I hit the save button. I could save all the users in a state, but I like how React auto-fetches when we come back to the page, so storing it in a state would be wrong too.
Does anyone have any suggestions for how to handle this situation with React Query? Thank you in advance for your help!