web-dev-qa-db-ja.com

反応アポロで削除を処理する方法

私のような突然変異があります

mutation deleteRecord($id: ID) {
    deleteRecord(id: $id) {
        id
    }
}

別の場所に要素のリストがあります。

サーバーから戻ることができるものがありますか?リストを更新するにはどうすればよいですか?

より一般的には、apollo/graphqlで削除を処理するためのベストプラクティスは何ですか?

20
derekdreery

グッドプラクティススタイルかどうかはわかりませんが、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);
15
vwrobel

以下は、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;
10
sinned

個人的に、削除されたアイテムの数を表すintを返します。次に、updateQueriesを使用して、キャッシュからドキュメントを削除します。

4
Siyfion

これらの答えはすべて、クエリ指向のキャッシュ管理を前提としています。

IDが_1_のuserを削除し、このユーザーがアプリ全体の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)
}
_
1
pie6k