So taking a look at the Apollo useMutation example in the docs https://www.apollographql.com/docs/react/data/mutations/#tracking-loading-and-error-states
function Todos() {
...
const [
updateTodo,
{ loading: mutationLoading, error: mutationError },
] = useMutation(UPDATE_TODO);
...
return data.todos.map(({ id, type }) => {
let input;
return (
<div key={id}>
<p>{type}</p>
<form
onSubmit={e => {
e.preventDefault();
updateTodo({ variables: { id, type: input.value } });
input.value = '';
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Update Todo</button>
</form>
{mutationLoading && <p>Loading...</p>}
{mutationError && <p>Error :( Please try again</p>}
</div>
);
});
}
This seems to have a major flaw (imo), updating any of the todos will show the loading state for every single todo, not just the one that has the pending mutation.
And this seems to stem from a larger problem: there's no way to track the state of multiple calls to the same mutation. So even if I did want to only show the loading state for the todos that were actually loading, there's no way to do that since we only have the concept of "is loading" not "is loading for todo X".
Besides manually tracking loading state outside of Apollo, the only decent solution I can see is splitting out a separate component, use that to render each Todo instead of having that code directly in the Todos component, and having those components each initialize their own mutation. I'm not sure if I think that's a good or bad design, but in either case it doesn't feel like I should have to change the structure of my components to accomplish this.
And this also extends to error handling. What if I update one todo, and then update another while the first update is in progress. If the first call errors, will that be visible at all in the data
returned from useMutation
? What about the second call?
Is there a native Apollo way to fix this? And if not, are there options for handling this that may be better than the ones I've mentioned?
Code Sandbox: https://codesandbox.io/s/v3mn68xxvy
mutationLoading
. state that you pass to your todos. the same state gets passed to all of them, so even if apollo had something you want, your code still wouldn't be making use of it. it would have to be something likeloadingId === id
at the very least. Anyways your problem is completely solved by callinguseMutation
at the item level, not the list level. that's not a workaround, it's perfectly sane solution – aziumisLoading
with the knowledge of which variable was being passed to the mutation, though I would consider that to be a much worse solution – aziumloadingId === id
, butloadingId
isn't available. – Westonloading
would mean nothing if I don't know exactly which mutations are the ones actuallyloading
. – WestonTodos
component (for some reason) I would either lose that ability, or need to add some sort ofonLoading
callback to theTodo
components, and still manually keep track of loading state inTodos
. – Weston