我有像
这样的突变mutation deleteRecord($id: ID) {
deleteRecord(id: $id) {
id
}
}
在另一个地方我有一个元素列表。
我可以从服务器返回更好的东西,我该如何更新列表?
更一般地说,在apollo / graphql中处理删除的最佳做法是什么?
答案 0 :(得分:15)
我不确定它是良好做法风格但是我在这里是如何使用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);
答案 1 :(得分:8)
这是一个类似的解决方案,无需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;
答案 2 :(得分:4)
就个人而言,我返回int
,表示已删除的项目数。然后我使用updateQueries
从缓存中删除文档。
答案 3 :(得分:3)
对于Apollo v3,这对我有效:
const [deleteExpressHelp] = useDeleteExpressHelpMutation({
update: (cache, {data}) => {
cache.evict({
id: cache.identify({
__typename: 'express_help',
id: data?.delete_express_help_by_pk?.id,
}),
});
},
});
来自new docs:
从缓存的数组字段中过滤掉悬空的引用(例如上面的Deity.offspring示例)非常普遍,Apollo Client会自动为未定义读取函数的数组字段执行此过滤。
答案 4 :(得分:1)
当与突变相关的其余API可能返回http 204、404或500时,我遇到了同样的问题,即为此类突变选择合适的返回类型。
定义和任意类型,然后返回空(类型默认为空)是不正确的,因为您不知道发生了什么,即是否成功。
返回布尔值可以解决该问题,您知道该突变是否有效,但是您缺少一些信息,以防它不起作用,例如可以在FE上显示的更好的错误消息,例如,如果我们得到404,则可以返回“未找到”。
返回自定义类型有点强迫,因为它实际上不是您的架构或业务逻辑的类型,它只是用于解决rest和Graphql之间的“通信问题”。
我最终返回了一个字符串。如果成功,我可以返回资源ID / UUID或简单地单击“确定”,如果出错则返回错误消息。
不确定这是一种好的做法还是Graphql惯用的。
答案 5 :(得分:0)
所有这些答案都假定了面向查询的缓存管理。
如果我删除ID为user
的{{1}}并在整个应用程序的20个查询中引用了该用户怎么办?阅读上面的答案,我不得不假设我将不得不编写代码来更新所有这些缓存。这对于代码库的长期可维护性将是可怕的,并且将使任何重构成为噩梦。
我认为最好的解决方案是像1
这样的东西:
apolloClient.removeItem({__typeName: "User", id: "1"})
null
列表中过滤出该项目但是它还不存在
这可能是个好主意,甚至可能更糟(例如,它可能会破坏分页)
对此有一个有趣的讨论:https://github.com/apollographql/apollo-client/issues/899
对于这些手动查询更新,我会很小心。乍看起来,它很吸引人,但您的应用是否会增长,却不会。至少在其顶部创建一个可靠的抽象层,例如:
[User]
然后收集所有这些更新,并在最终更新中将其全部调用
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
}