Apollo Client delete Item from cache
Asked Answered
L

3

28

Hy I'm using the Apollo Client with React. I query the posts with many different variables. So I have one post in different "caches". Now I want to delete a post. So I need to delete this specific post from all "caches".

const client = new ApolloClient({
    link: errorLink.concat(authLink.concat(httpLink)),
    cache: new InMemoryCache()
});

Postquery:

export const POSTS = gql`
    query posts(
        $after: String
        $orderBy: PostOrderByInput
        $tags: JSONObject
        $search: String
        $orderByTime: Int
    ) {
        posts(
            after: $after
            orderBy: $orderBy
            tags: $tags
            search: $search
            orderByTime: $orderByTime
        ) {
            id
            title
            ...
        }
    }
`;

I tried it with the cache.modify(), which is undefined in my mutation([https://www.apollographql.com/docs/react/caching/cache-interaction/#cachemodify][1])

const [deletePost] = useMutation(DELETE_POST, {
        onError: (er) => {
            console.log(er);
        },
        update(cache, data) {
            console.log(cache.modify())//UNDEFINED!!!
            cache.modify({
                id: cache.identify(thread), //identify is UNDEFINED + what is thread
                fields: {
                    posts(existingPosts = []) {
                        return existingPosts.filter(
                            postRef => idToRemove !== readField('id', postRef)
                         );
                    }
                }
            })
        }
    });

I also used the useApolloClient() with the same result.

THX for any help.

Ligetti answered 31/7, 2020 at 13:27 Comment(0)
O
14

this option worked for me

const GET_TASKS = gql`
  query tasks($listID: String!) {
    tasks(listID: $listID) {
      _id
      title
      sort
    }
  }
`;

const REMOVE_TASK = gql`
  mutation removeTask($_id: String) {
    removeTask(_id: $_id) {
      _id
    }
  }
`;

const Tasks = () => {
  const { loading, error, data } = useQuery(GET_TASKS, {
    variables: { listID: '1' },
  });
  сonst [removeTask] = useMutation(REMOVE_TASK);

  const handleRemoveItem = _id => {
    removeTask({
      variables: { _id },
      update(cache) {
        cache.modify({
          fields: {
            tasks(existingTaskRefs, { readField }) {
              return existingTaskRefs.filter(
                taskRef => _id !== readField('_id', taskRef),
              );
            },
          },
        });
      },
    });
  };

  return (...);
};
Osculate answered 20/8, 2020 at 23:15 Comment(0)
P
80

Instead of using cache.modify you can use cache.evict, which makes the code much shorter:

deletePost({
    variables: { id },
    update(cache) {
        const normalizedId = cache.identify({ id, __typename: 'Post' });
        cache.evict({ id: normalizedId });
        cache.gc();
    }
});
Phallicism answered 19/3, 2021 at 18:14 Comment(4)
Is cache.gc() necessary in this case?Andradite
I think it is, apollographql.com/docs/react/caching/garbage-collection/… says: "Evicting an object often makes other cached objects unreachable. Because of this, you should call cache.gc after evicting one or more objects from the cache."Phallicism
This should be the accepted answer!Polyphemus
i like it. simple and workingChronometry
O
14

this option worked for me

const GET_TASKS = gql`
  query tasks($listID: String!) {
    tasks(listID: $listID) {
      _id
      title
      sort
    }
  }
`;

const REMOVE_TASK = gql`
  mutation removeTask($_id: String) {
    removeTask(_id: $_id) {
      _id
    }
  }
`;

const Tasks = () => {
  const { loading, error, data } = useQuery(GET_TASKS, {
    variables: { listID: '1' },
  });
  сonst [removeTask] = useMutation(REMOVE_TASK);

  const handleRemoveItem = _id => {
    removeTask({
      variables: { _id },
      update(cache) {
        cache.modify({
          fields: {
            tasks(existingTaskRefs, { readField }) {
              return existingTaskRefs.filter(
                taskRef => _id !== readField('_id', taskRef),
              );
            },
          },
        });
      },
    });
  };

  return (...);
};
Osculate answered 20/8, 2020 at 23:15 Comment(0)
T
4

You can pass your updater to the useMutation or to the deletePost. It should be easier with deletePost since it probably knows what it tries to delete:

    deletePost({
        variables: { idToRemove },
        update(cache) {
            cache.modify({
                fields: {
                    posts(existingPosts = []) {
                        return existingPosts.filter(
                            postRef => idToRemove !== readField('id', postRef)
                        );
                    },
                },
            });
        },
    });

You should change variables to match your mutation. This should work since posts is at top level of your query. With deeper fields you'll need a way to get the id of the parent object. readQuery or a chain of readField from the top might help you with that.

Tarrel answered 31/7, 2020 at 13:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.