繁体   English   中英

我如何处理反应阿波罗中的删除

[英]How do I handle deletes in react-apollo

我有一个像

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);

这是一个类似的解决方案,无需 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;

所有这些答案都假定面向查询的缓存管理。

如果我删除user 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)
}

对于 Apollo v3,这对我有用:

const [deleteExpressHelp] = useDeleteExpressHelpMutation({
  update: (cache, {data}) => {
    cache.evict({
      id: cache.identify({
        __typename: 'express_help',
        id: data?.delete_express_help_by_pk?.id,
      }),
    });
  },
});

从新文档

从缓存的数组字段中过滤悬空引用(如上面的 Deity.offspring 示例)非常普遍,以至于 Apollo Client 会自动为未定义读取函数的数组字段执行此过滤。

就个人而言,我返回一个int表示删除的项目数。 然后我使用updateQueries从缓存中删除文档。

当与突变相关的其余 API 可能返回 http 204、404 或 500 时,我遇到了相同的问题,为此类突变选择适当的返回类型。

定义和任意类型然后返回空值(默认情况下类型可以为空)似乎不正确,因为您不知道发生了什么,这意味着它是否成功。

返回一个布尔值可以解决这个问题,你知道突变是否有效,但你缺乏一些信息,以防它不起作用,比如你可以在 FE 上显示的更好的错误消息,例如,如果我们得到 404 我们可以返回“未找到”。

返回自定义类型感觉有点强迫,因为它实际上不是您的架构或业务逻辑的类型,它只是用于解决 rest 和 Graphql 之间的“通信问题”。

我最终返回了一个 string 如果成功,我可以返回资源 ID/UUID 或简单地“确定”,并在出错时返回错误消息。

不确定这是一个好的做法还是 Graphql 惯用的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM