question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Nesting .modify() results in React unmounted warning

See original GitHub issue

Edit: see https://github.com/apollographql/apollo-client/issues/7061#issuecomment-699041546 for a description of the current issue


https://www.apollographql.com/docs/react/caching/cache-interaction/#cachemodify has examples of modifying a root query field and the field of a normalized object. I’m wondering how to modify a nested field of a root query field, Query.currentUser.favoriteReviews:

The old way with read/writeQuery:

const [removeReview] = useMutation(REMOVE_REVIEW_MUTATION, {
  update: (cache) => {
    const { currentUser } = cache.readQuery({ query: READ_USER_FAVORITES })
    cache.writeQuery({
      query: READ_USER_FAVORITES,
      data: {
        currentUser: {
          ...currentUser,
          favoriteReviews: currentUser.favoriteReviews.filter(
            (review) => review.id !== id
          ),
        },
      },
    })
  },
})

I’m looking for something like this (which doesn’t work because fields.currentUser is supposed to be a function):

  const [removeReview] = useMutation(REMOVE_REVIEW_MUTATION, {
    update: (cache) => {
      cache.modify({
        fields: {
          currentUser: {
            favoriteReviews: (currentUserRef, { readField }) =>
              readField('favoriteReviews', currentUserRef).filter(
                (reviewRef) => readField('id', reviewRef) !== id
              ),
          },
        },
      })
    },
  })

In this case, the currentUser object is not normalized. If it were, I could do:

  const [removeReview] = useMutation(REMOVE_REVIEW_MUTATION, {
    update: (cache) => {
      const { currentUser } = cache.readQuery({ query: READ_USER_FAVORITES })
      cache.modify({
        id: cache.identify(currentUser),
        fields: {
          favoriteReviews: (favoriteReviewRefs, { readField }) =>
            favoriteReviewRefs.filter(
              (reviewRef) => readField('id', reviewRef) !== id
            ),
        },
      })
    }
  })

Although it feels weird to mix readQuery and modify.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

12reactions
kieranbentoncommented, Nov 20, 2020

Firstly, thanks for the information in here - I’ve struggled to find the information in https://github.com/apollographql/apollo-client/issues/7061#issuecomment-698996938 documented anywhere. Am I missing something or should the documentation be updated with a more complex example to show how to modify nested data, which I thought was quite a common scenario but perhaps not?

Secondly, does anyone know if there is any way to get Typescript types for cache.modify? Right now although this method works it feels extremely fragile to me as its not tied to any of my generated TS types for my queries.

5reactions
benjamncommented, Sep 25, 2020

@lorensr A nested call to cache.modify should work?

const [removeReview] = useMutation(REMOVE_REVIEW_MUTATION, {
  update: (cache) => {
    cache.modify({
      fields: {
        currentUser(currentUserRef) {
          cache.modify({
            id: currentUserRef.__ref,
            fields: {
              favoriteReviews(reviews, { readField }) {
                return reviews.filter(review => readField('id', review) !== id)
              },
            },
          })
          // Keep Query.currentUser unchanged.
          return currentUserRef
        },
      },
    })
  },
})

I also don’t see how to delete an object from the cache? Looks like the DELETE sentinel is just for deleting an object’s field. And when you remove a comment ref from a list of comment refs, the comment object is still in the cache.

You can use cache.evict({ id: cache.identify(...) }) to delete the whole object, though I’m open to adding options to cache.modify to facilitate deletion.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can't perform a React state update on an unmounted ...
Here is a simple solution for this. This warning is due to when we do some fetch request while that request ...
Read more >
Prevent React setState on unmounted Component
Warning : Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted ......
Read more >
React v17.0 Release Candidate: No New Features
This breaks e.stopPropagation() : if a nested tree has stopped propagation of an event, the outer tree would still receive it. This made...
Read more >
The last guide to the useEffect Hook you'll ever need
React's effects are a completely different animal than the lifecycle ... tasks at particular lifecycle phases (e.g., on component unmount).
Read more >
How To Handle Async Data Loading, Lazy Loading, and Code ...
When you set the data, the Hook change will trigger a components re-render. When the component re-renders, the getRiverInformation function will ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found