Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

After a mutation, how do I update the affected data across views? [duplicate]

enter image description here

I have both the getMovies query and addMovie mutation working. When addMovie happens though, I'm wondering how to best update the list of movies in "Edit Movies" and "My Profile" to reflect the changes. I just need a general/high-level overview, or even just the name of a concept if it's simple, on how to make this happen.

My initial thought was just to hold all of the movies in my Redux store. When the mutation finishes, it should return the newly added movie, which I can concatenate to the movies of my store.

After "Add Movie", it would pop back to the "Edit Movies" screen where you should be able to see the newly added movie, then if you go back to "My Profile", it'd be there too.

Is there a better way to do this than holding it all in my own Redux store? Is there any Apollo magic I don't know about that could possibly handle this update for me?


EDIT: I discovered the idea of updateQueries: http://dev.apollodata.com/react/cache-updates.html#updateQueries I think this is what I want (please let me know if this is not the right approach). This seems better than the traditional way of using my own Redux store.

// this represents the 3rd screen in my picture
const AddMovieWithData = compose(
  graphql(searchMovies, {
    props: ({ mutate }) => ({
      search: (query) => mutate({ variables: { query } }),
    }),
  }),
  graphql(addMovie, {
    props: ({ mutate }) => ({
      addMovie: (user_id, movieId) => mutate({
        variables: { user_id, movieId },
        updateQueries: {
          getMovies: (prev, { mutationResult }) => {
            // my mutation returns just the newly added movie
            const newMovie = mutationResult.data.addMovie;

            return update(prev, {
              getMovies: {
                $unshift: [newMovie],
              },
            });
          },
        },
      }),
    }),
  })
)(AddMovie);

After addMovie mutation, this properly updates the view in "My Profile" because it uses the getMovies query (woah)! I'm then passing these movies as props into "Edit Movies", so how do I update it there as well? Should I just have them both use the getMovies query? Is there a way to pull the new result of getMovies out of the store, so I can reuse it on "Edit Movies" without doing the query again?


EDIT2: Wrapping MyProfile and EditMovies both with getMovies query container seems to work fine. After addMovie, it's updated in both places due to updateQueries on getMovies. It's fast too. I think it's being cached?

It all works, so I guess this just becomes a question of: Was this the best approach?

like image 522
atkayla Avatar asked Oct 19 '16 17:10

atkayla


2 Answers

The answer to the question in the title is

Use updateQueries to "inform` the queries that drive the other views that the data has changed (as you discovered).

This topic gets ongoing discussion in the react-apollo slack channel, and this answer is the consensus that I'm aware of: there's no obvious alternative.

Note that you can update more than one query (that's why the name is plural, and the argument is an object containing keys that match the name of all the queries that need updating).

As you may guess, this "pattern" does mean that you need to be careful in designing and using queries to make life easy and maintainable in designing mutations. More common queires means less chance that you miss one in a mutation updateQueries action.

like image 56
GreenAsJade Avatar answered Sep 27 '22 20:09

GreenAsJade


The Apollo Client only updates the store on update mutations. So when you use create or delete mutations you need to tell Apollo Client how to update. I had expected the store to update automatically but it doesn’t…

I have founded a workaround with resetStore just after doing your mutation. You reset the store just after doing the mutation. Then when you will need to query, the store is empty, so apollo refetch fresh data.

here is the code:

import { withApollo } from 'react-apollo'

...

  deleteCar = async id => {
    await this.props.deleteCar({
      variables: { where: {
        id: id
      } },
    })
    this.props.client.resetStore().then(data=> {
      this.props.history.push('/cars')
    })
  }


...


export default compose(
  graphql(POST_QUERY, {
    name: 'carQuery',
    options: props => ({
      fetchPolicy: 'network-only',
      variables: {
        where: {
          id: props.match.params.id,
        }
      },
    }),
  }),
  graphql(DELETE_MUTATION, {
    name: 'deleteCar',
  }),
  withRouter,
  withApollo
)(DetailPage)

The full code is here: https://github.com/alan345/naperg Ther error before the hack resetStore enter image description here

like image 42
Alan Avatar answered Sep 27 '22 20:09

Alan