因此,请看文档https://www.apollographql.com/docs/react/data/mutations/#tracking-loading-and-error-states
中的Apollo useMutation示例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>
);
});
}
这似乎有一个主要缺陷(imo),更新任何待办事项都将显示每个待办事项的加载状态,而不仅仅是具有待定突变的待办事项。
这似乎是由一个更大的问题引起的:没有办法跟踪对同一突变的多次调用的状态。因此,即使我只想显示实际正在加载的待办事项的加载状态,也无法做到这一点,因为我们只有“正在加载”而不是“正在加载待办事项X”的概念。
除了手动跟踪Apollo之外的加载状态外,我看到的唯一体面的解决方案是拆分一个单独的组件,使用该组件呈现每个Todo,而不是直接在Todos组件中包含该代码,并让这些组件各自初始化其代码。自己的突变。我不确定这是好的设计还是坏的设计,但是在任何一种情况下,我都不认为必须更改组件的结构来实现此目的。
这也扩展到错误处理。如果我更新一个待办事项,然后在进行第一次更新时又更新另一个,该怎么办?如果首次通话出错,在data
返回的useMutation
中是否完全可见?那第二通电话呢?
是否有本地的Apollo方法来解决此问题?如果没有,有没有比我上面提到的更好的处理方法了?
答案 0 :(得分:3)
诚然,文档中的示例应重写为更加清晰。还有很多其他问题。
useQuery
和useMutation
挂钩仅设计用于一次跟踪单个操作的加载,错误和结果状态。该操作的变量可能会更改,可能会使用fetchMore
重新提取或附加到该变量,但最终,您仍在处理该操作。您不能使用单个挂钩来跟踪多个操作的单独状态。为此,您需要多个钩子。
在这种形式的情况下,如果提前知道输入字段,则可以将钩子拆分为同一组件中的多个:
const [updateA, { loading: loadingA, error: errorA }] = useMutation(YOUR_MUTATION)
const [updateB, { loading: loadingB, error: errorB }] = useMutation(YOUR_MUTATION)
const [updateC, { loading: loadingC, error: errorC }] = useMutation(YOUR_MUTATION)
如果您要处理可变数量的字段,那么我们必须将此逻辑分解为单独的逻辑,因为我们无法在循环内声明钩子。这不是Apollo API的限制,而是钩子本身背后的魔术的副作用。
const ToDo = ({ id, type }) => {
const [value, setValue] = useState('')
const options = { variables = { id, type: value } }
const const [updateTodo, { loading, error }] = useMutation(UPDATE_TODO, options)
const handleChange = event => setValue(event.target.value)
return (
<div>
<p>{type}</p>
<form onSubmit={updateTodo}>
<input
value={value}
onChange={handleChange}
/>
<button type="submit">Update Todo</button>
</form>
</div>
)
}
// back in our original component...
return data.todos.map(({ id, type }) => (
<Todo key={id} id={id} type={type] />
))