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 チャネルで継続的に議論されています。この回答は、私が認識しているコンセンサスです。明らかな代替手段はありません。

複数のクエリを更新できることに注意してください (そのため、名前は複数形であり、引数は、更新が必要なすべてのクエリの名前に一致するキーを含むオブジェクトです)。

ご想像のとおり、この「パターン」は、クエリの設計と使用に注意して、ミューテーションの設計を容易にし、保守しやすくする必要があることを意味します。updateQueriesより一般的なクエリは、突然変異アクションで 1 つを見逃す可能性が少ないことを意味します。

于 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 に答える