您如何使用 Apollo Client 有效地批处理 GraphQL 突变?
How do you effectively batch GraphQL mutations using Apollo Client?
我在使用 GraphQL 突变处理快速数据库更新时遇到问题,特别是通过来自 Apollo Client 的 react-hooks
的 useQuery
和 useMutation
。我有一个 table 表示来自数据库的数据,4 列是由复选框表示的布尔值,还有其他输入。选中该复选框会向数据库发送请求以将值设置为 true,然后重新获取(通过 refetch
命令式或 refetchQueries
)查询并更新 table.
我的复选框组件:
export const TableCheckbox: <T extends VasaRecord & DomainEntity, K extends keyof T>(props: TableInputProps<T, K>) => ReactElement = ({
value, // Boolean column value
record, //Entire data record
dataIndex //Accessor on record where value is located
}) => {
const [checked, setChecked] = useState<boolean>(value as boolean);
// useMutation function
const { updateEntity } = useContext(
TrackerContext
);
useEffect(() => {
setChecked(value as boolean);
}, [value]);
const handleCheck = (e: CheckboxChangeEvent) => {
const val = e.target.checked;
setChecked(val);
const newRecord = { id: record.key, [dataIndex]: val };
updateEntity({
variables: { entityTracker: JSON.stringify(newRecord) }
}).then((res: any) => {
console.log(res);
});
};
return (
<span className="checkbox-wrapper" onClick={disableClickSelect}>
<Checkbox checked={checked} onChange={handleCheck} />
</span>
);
};
但是,此周期可能需要 1-2 整秒,这不是查看反映的更改的可用响应时间。我通过在内部管理复选框状态并在处理 mutations/queries 和返回新数据之前更新它来解决这个问题。
这在大多数情况下工作正常,但当复选框或输入等连续快速更新时会导致奇怪的行为,并且由于未触发它们的请求而可能会错过一些更新。更糟糕的是,因为我在前端管理状态,它可能会显示不准确的信息,然后在最后一个查询 returns 时被覆盖。我可以在请求为 运行 时禁用输入,但这感觉就像作弊。除非您专门尝试使用制表符和 space 尽可能快地检查,否则它并不是很明显,但仍然不好。
答案是否使用 Apollo 提供的 in-memory cache 来存储客户端数据以便即时更新?这听起来可行,但我想知道如果更新发送得太快以至于它们相互干扰,我是否会遇到同样的问题,而且这将意味着重写所有代码以在任何地方与数据库交互,即使是在这个地方不是问题(除非我弄错了),所以我宁愿尽可能避免它。
是否有一种有效的方法来批量突变或以其他方式防止它们相互干扰?我的整个方法有缺陷吗?当单独触发更新或由用户操作触发更新时,此模式工作正常,但它似乎根本无法很好地处理实时更新,因此非常感谢任何见解或替代方案!
听起来你应该利用 Apollo 的 optimistic UI features。您可以为您的突变指定一个 optimisticResponse
,它将用作服务器实际响应的占位符。这允许您的 UI 平滑地更改以响应用户操作,即使需要一段时间才能从服务器获得响应。乐观响应应用于缓存本身,因此您应用程序的任何其他部分也会立即反映出变化。不幸的是,它不适用于 refetch
,但理想情况下您应该使用 update
而不是重新获取查询(而且 optimisticResponse 确实 可以与任何 update
你提供的逻辑)。
我在使用 GraphQL 突变处理快速数据库更新时遇到问题,特别是通过来自 Apollo Client 的 react-hooks
的 useQuery
和 useMutation
。我有一个 table 表示来自数据库的数据,4 列是由复选框表示的布尔值,还有其他输入。选中该复选框会向数据库发送请求以将值设置为 true,然后重新获取(通过 refetch
命令式或 refetchQueries
)查询并更新 table.
我的复选框组件:
export const TableCheckbox: <T extends VasaRecord & DomainEntity, K extends keyof T>(props: TableInputProps<T, K>) => ReactElement = ({
value, // Boolean column value
record, //Entire data record
dataIndex //Accessor on record where value is located
}) => {
const [checked, setChecked] = useState<boolean>(value as boolean);
// useMutation function
const { updateEntity } = useContext(
TrackerContext
);
useEffect(() => {
setChecked(value as boolean);
}, [value]);
const handleCheck = (e: CheckboxChangeEvent) => {
const val = e.target.checked;
setChecked(val);
const newRecord = { id: record.key, [dataIndex]: val };
updateEntity({
variables: { entityTracker: JSON.stringify(newRecord) }
}).then((res: any) => {
console.log(res);
});
};
return (
<span className="checkbox-wrapper" onClick={disableClickSelect}>
<Checkbox checked={checked} onChange={handleCheck} />
</span>
);
};
但是,此周期可能需要 1-2 整秒,这不是查看反映的更改的可用响应时间。我通过在内部管理复选框状态并在处理 mutations/queries 和返回新数据之前更新它来解决这个问题。
这在大多数情况下工作正常,但当复选框或输入等连续快速更新时会导致奇怪的行为,并且由于未触发它们的请求而可能会错过一些更新。更糟糕的是,因为我在前端管理状态,它可能会显示不准确的信息,然后在最后一个查询 returns 时被覆盖。我可以在请求为 运行 时禁用输入,但这感觉就像作弊。除非您专门尝试使用制表符和 space 尽可能快地检查,否则它并不是很明显,但仍然不好。
答案是否使用 Apollo 提供的 in-memory cache 来存储客户端数据以便即时更新?这听起来可行,但我想知道如果更新发送得太快以至于它们相互干扰,我是否会遇到同样的问题,而且这将意味着重写所有代码以在任何地方与数据库交互,即使是在这个地方不是问题(除非我弄错了),所以我宁愿尽可能避免它。
是否有一种有效的方法来批量突变或以其他方式防止它们相互干扰?我的整个方法有缺陷吗?当单独触发更新或由用户操作触发更新时,此模式工作正常,但它似乎根本无法很好地处理实时更新,因此非常感谢任何见解或替代方案!
听起来你应该利用 Apollo 的 optimistic UI features。您可以为您的突变指定一个 optimisticResponse
,它将用作服务器实际响应的占位符。这允许您的 UI 平滑地更改以响应用户操作,即使需要一段时间才能从服务器获得响应。乐观响应应用于缓存本身,因此您应用程序的任何其他部分也会立即反映出变化。不幸的是,它不适用于 refetch
,但理想情况下您应该使用 update
而不是重新获取查询(而且 optimisticResponse 确实 可以与任何 update
你提供的逻辑)。