J'ai une mutation comme
mutation deleteRecord($id: ID) {
deleteRecord(id: $id) {
id
}
}
et dans un autre endroit, j'ai une liste d'éléments.
Y a-t-il quelque chose de mieux que je pourrais retourner du serveur, et comment dois-je mettre à jour la liste?
Plus généralement, quelle est la meilleure pratique pour gérer les suppressions dans apollo/graphql?
Je ne suis pas sûr que ce soit style de bonne pratique mais voici comment je gère la suppression d'un élément dans react-apollo avec updateQueries:
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);
Voici une solution similaire qui fonctionne sans underscore.js. Il est testé avec react-apollo
dans la version 2.1.1. et crée un composant pour un bouton de suppression:
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;
Personnellement, je retourne un int
qui représente le nombre d'éléments supprimés. J'utilise ensuite le updateQueries
pour supprimer le ou les documents du cache.
Toutes ces réponses supposent une gestion du cache orientée requêtes.
Que faire si je supprime user
avec l'ID 1
Et que cet utilisateur est référencé dans 20 requêtes sur l'ensemble de l'application? En lisant les réponses ci-dessus, je devrais supposer que je devrai écrire du code pour mettre à jour le cache de chacun d'eux. Ce serait terrible dans la maintenabilité à long terme de la base de code et ferait de toute refactorisation un cauchemar.
À mon avis, la meilleure solution serait quelque chose comme apolloClient.removeItem({__typeName: "User", id: "1"})
qui:
null
[User]
dans n'importe quelle requêteMais ça n'existe pas (encore)
Ce pourrait être une excellente idée, ou cela pourrait être encore pire (par exemple, cela pourrait casser la pagination)
Il y a une discussion intéressante à ce sujet: https://github.com/apollographql/apollo-client/issues/899
Je serais prudent avec ces mises à jour manuelles des requêtes. Cela semble appétissant au début, mais ce ne sera pas le cas si votre application grandit. Créez au moins une couche d'abstraction solide au-dessus, par exemple:
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
}
puis collectez toutes ces mises à jour et appelez-les toutes dans la mise à jour finale
function handleUserDeleted(userId, client) {
removeUserFromMyQuery(userId, client)
removeUserFromSearchQuery(userId, client)
removeIdFrom20MoreQueries(userId, client)
}