我有一种像突变的情况
mutation deleteRecord($id: ID) {
deleteRecord(id: $id) {
id
}
}
在另一个地方,我有一份元素列表。
从服务器返回是否有更好的内容,并且应该如何更新列表?
更普遍地说,在Apollo/GraphQL中处理删除的最佳实践是什么?
我有一种像突变的情况
mutation deleteRecord($id: ID) {
deleteRecord(id: $id) {
id
}
}
在另一个地方,我有一份元素列表。
从服务器返回是否有更好的内容,并且应该如何更新列表?
更普遍地说,在Apollo/GraphQL中处理删除的最佳实践是什么?
我不确定这是一个好的实践方式,但以下是我如何使用updateQueries在react-apollo中处理删除项目的方法:
import { graphql, compose } from 'react-apollo';
import gql from 'graphql-tag';
import update from 'react-addons-update';
import _ from 'underscore';
const SceneCollectionsQuery = gql `
query SceneCollections {
myScenes: selectedScenes (excludeOwner: false, first: 24) {
edges {
node {
...SceneCollectionScene
}
}
}
}`;
const DeleteSceneMutation = gql `
mutation DeleteScene($sceneId: String!) {
deleteScene(sceneId: $sceneId) {
ok
scene {
id
active
}
}
}`;
const SceneModifierWithStateAndData = compose(
...,
graphql(DeleteSceneMutation, {
props: ({ mutate }) => ({
deleteScene: (sceneId) => mutate({
variables: { sceneId },
updateQueries: {
SceneCollections: (prev, { mutationResult }) => {
const myScenesList = prev.myScenes.edges.map((item) => item.node);
const deleteIndex = _.findIndex(myScenesList, (item) => item.id === sceneId);
if (deleteIndex < 0) {
return prev;
}
return update(prev, {
myScenes: {
edges: {
$splice: [[deleteIndex, 1]]
}
}
});
}
}
})
})
})
)(SceneModifierWithState);
${type}:${id}
作为我的缓存键)。这样做也可以吗? - derekdreeryupdateQuery
时,只有指定的代码应用于先前的查询结果。在我发布的代码中,我得到的唯一变化是我的删除项从列表SceneCollections.myScenes中删除了。此外,如果我有另一个查询来获取user {id,sceneCounter}
,我将不得不手动从updateQueries更新sceneCounter:即使我的DeleteSceneMutation返回更新的user {id,sceneCounter}
,当我使用updateQueries时,其他查询结果不会被更新。不确定它是否回答了你的问题,我的apollo知识相当有限... - vwrobelSceneCollections(id:“xyz”)
返回的多个结果怎么办? - Jazzy这里有一个类似的解决方案,它不需要使用 underscore.js。它已经在版本号为 2.1.1 的 react-apollo
中进行了测试,并为删除按钮创建了一个组件:
import React from "react";
import { Mutation } from "react-apollo";
const GET_TODOS = gql`
{
allTodos {
id
name
}
}
`;
const DELETE_TODO = gql`
mutation deleteTodo(
$id: ID!
) {
deleteTodo(
id: $id
) {
id
}
}
`;
const DeleteTodo = ({id}) => {
return (
<Mutation
mutation={DELETE_TODO}
update={(cache, { data: { deleteTodo } }) => {
const { allTodos } = cache.readQuery({ query: GET_TODOS });
cache.writeQuery({
query: GET_TODOS,
data: { allTodos: allTodos.filter(e => e.id !== id)}
});
}}
>
{(deleteTodo, { data }) => (
<button
onClick={e => {
deleteTodo({
variables: {
id
}
});
}}
>Delete</button>
)}
</Mutation>
);
};
export default DeleteTodo;
所有这些答案都假定了以查询为导向的缓存管理。
如果我删除ID为1的“用户”,并且该用户在整个应用程序中引用了20个查询,那怎么办?根据上面的答案,我必须假设我将不得不编写代码来更新所有这些缓存。这对于代码库的长期可维护性来说是极其糟糕的,也会使任何重构成为一场噩梦。
我认为最好的解决方案是像apolloClient.removeItem({__typeName: "User", id: "1"})
这样的东西:
null
[User]
列表中的此项但它还不存在(目前)
这可能是一个很好的想法,也可能更糟糕(例如,它可能会破坏分页)
有关此问题的有趣讨论:https://github.com/apollographql/apollo-client/issues/899
对于那些手动查询更新,我要小心一点。一开始看起来很有吸引力,但如果您的应用程序增长了,这种方法将不再适用。请至少在其上创建一个稳定的抽象层,例如:
const MY_QUERY = gql``;
// it's local 'cleaner' - relatively easy to maintain as you can require proper cleaner updates during code review when query will change
export function removeUserFromMyQuery(apolloClient, userId) {
// clean here
}
然后,收集所有这些更新并在最终更新中调用它们。
function handleUserDeleted(userId, client) {
removeUserFromMyQuery(userId, client)
removeUserFromSearchQuery(userId, client)
removeIdFrom20MoreQueries(userId, client)
}
const [deleteExpressHelp] = useDeleteExpressHelpMutation({
update: (cache, {data}) => {
cache.evict({
id: cache.identify({
__typename: 'express_help',
id: data?.delete_express_help_by_pk?.id,
}),
});
},
});
个人而言,我会返回一个int
表示删除的项目数量。然后使用updateQueries
从缓存中移除文档。
updateQueries
删除记录的例子吗?特别是当它们在树中出现在多个位置时。 - derekdreeryupdateQueries
来删除项目。 - Dunos当与变异相关的REST API可能返回http 204、404或500时,我面临了选择适当的返回类型的相同问题。
定义任意类型,然后返回null(默认情况下类型可为空)似乎不正确,因为您不知道发生了什么,也就是它是否成功。
返回布尔值解决了这个问题,您知道变异是否起作用,但如果它没有起作用,则缺少一些信息,例如更好的错误消息,您可以在FE上显示该消息,例如,如果我们得到404,我们可以返回“未找到”。
返回自定义类型感觉有点强制,因为它实际上不是您模式或业务逻辑的类型,它只是用于修复REST和GraphQL之间的“通信问题”。
最终我返回一个字符串。我可以返回资源ID / UUID或成功时简单地返回“ok”,并在出现错误时返回错误消息。
不确定这是否是良好的做法或GraphQL惯用语。