7

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?

4

2 回答 2

2

标题中问题的答案是

用于updateQueries“通知”驱动其他视图的查询数据已更改(如您所见)。

这个话题在 react-apollo slack 频道中得到了持续的讨论,这个答案是我所知道的共识:没有明显的替代方案。

请注意,您可以更新多个查询(这就是名称为复数的原因,并且参数是一个对象,其中包含与所有需要更新的查询的名称匹配的键)。

正如您可能猜到的那样,这种“模式”确实意味着您在设计和使用查询时需要小心,以便在设计突变时使生活变得简单和可维护。更常见的 queires 意味着您在突变updateQueries动作中错过的机会更少。

于 2016-10-19T22:38:52.347 回答
1

Apollo 客户端仅在更新突变时更新存储。因此,当您使用创建或删除突变时,您需要告诉 Apollo 客户端如何更新。我原以为商店会自动更新,但它没有……</p>

resetStore在您进行突变后,我已经建立了一种解决方法。您在进行突变后重置商店。然后当你需要查询时,存储是空的,所以 apollo 重新获取新数据。

这是代码:

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)

完整代码在这里:https ://github.com/alan345/naperg 黑客攻击前的错误resetStore 在此处输入图像描述

于 2018-05-16T16:29:37.357 回答