apollo-client: writeQuery does not work with 2.0

I have a very simple query:

  query unreadChatMessagesCount {
    unreadChatMessagesCount
  }

unreadChatMessagesCount defined in the schema as Int!

And I am using the following code to create a subscription for the query:

    const q = this.props.client.watchQuery({
      query: totalUnreadCountQuery,
    });

    q.subscribe({
      next: console.log,
      error: console.log,
    });

I am using the default fetchPolicy, without polling.

The initial execution of the query works as expected and the result is printed to the log.

Then, my code does:

      const data = client.readQuery({ query: totalUnreadCountQuery });
      data.unreadChatMessagesCount = data.unreadChatMessagesCount + 1;
      client.writeQuery({ query: totalUnreadCountQuery, data });

The store updates and I can see it’s new value in the store, but the next of the watchQuery Observable is not triggered.

Also trying to execute it using react-apollo - but the props does not update.

UPDATE:

I did some debugging, and I think that maybe a call for broadcastQueries is missing after updating the store manually… adding this:

 client.queryManager.broadcastQueries();

After the writeQuery call did the trick and provides a temporary workaround.

Intended outcome:

Store should update, then trigger the next of the Observable, otherwise the subscribers can’t tell that the data has changed.

Actual outcome:

Store updates with new value, but the Observable’s next is not triggered.

How to reproduce the issue:

Use writeQuery to update a query that created with watchQuery (or with react-apollo HOC)

Version

    "apollo-cache": "^1.0.0",
    "apollo-cache-inmemory": "^1.0.0",
    "apollo-client": "^2.0.1",
    "apollo-link": "^1.0.0",
    "apollo-link-http": "^1.0.0",
    "graphql-anywhere": "^4.0.0",
    "graphql-tag": "^2.5.0",
    "react-apollo": "^2.0.0",

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 21
  • Comments: 45 (18 by maintainers)

Commits related to this issue

Most upvoted comments

The issue outlined in the reproduction from https://github.com/apollographql/apollo-client/issues/2415#issuecomment-459545805 points to a shortcoming in our docs. Our docs are a bit misleading with regards to expecting cache.writeQuery to always lead to watched queries being re-broadcast. If the following from the repro

this.apollo.cache.writeQuery({
  query: allPosts,
  data
});

is updated to be

this.apollo.client.writeQuery({
  query: allPosts,
  data
});

everything will work. This is because client.writeQuery takes care of calling the additionally required client.initQueryManager().broadcastQueries() automatically. Right now our docs lead people to believe that cache.writeQuery will make this happen, which is sort of true, but it depends on where it’s being used. If the repro was updated to use the mutate update option like this

@task
createPost = function*() {
  const result = yield this.apollo.mutate(
    {
      mutation: createPost,
      variables: {
        content: "A new post"
      },
      update: (cache, { data: { post: newPost } }) => {
        this.set("createdPosts", [...this.createdPosts, newPost]);
        const data = this.apollo.cache.readQuery({
          query: allPosts
        });
        data.allPosts = [...data.allPosts, newPost];
        this.apollo.cache.writeQuery({
          query: allPosts,
          data,
        });
      }
    },
    "post"
  );
}

then in that case calling cache.writeQuery would trigger the necessary re-broadcast, since update takes care of this.

Long story short, we should clarify this in the docs by adding a note somewhere in the Updating the cache section. I also think it would make sense to expose the Apollo Cache API in the left hand menu of the docs, down in the API section with Apollo Client and React Apollo. We could add extra details like this to those specific cache API docs, which would help with discovery.

I’ll create a new issue to track this work.

I tried all the following:

  • updateQuery
  • updateQuery + client.queryManager.broadcastQueries()
  • readQuery + writeQuery
  • readQuery + writeQuery + client.queryManager.broadcastQueries()

None of the above made the Query re-render.

I’m avoiding this issue for now by not going to the cache:

const results = await this.props.client.query({
  query: getVenuesQuery,
  variables: {
    name: inputValue,
  },
  fetchPolicy: 'network-only'
});

Confirming this happens to me too, and adding client.queryManager.broadcastQueries() as mentioned above solves the issue!

@jbaxleyiii I created a reproduction here: https://github.com/dotansimha/apollo-client-unhandled-expection Under the directory write-query.

Note that the console.log here: https://github.com/dotansimha/apollo-client-unhandled-expection/blob/master/write-query/index.js#L111 it called only once, but when you uncomment this line: https://github.com/dotansimha/apollo-client-unhandled-expection/blob/master/write-query/index.js#L128

it called twice…

And yeah @20matan is right, it also happens with writeFragment

Reproduction

I believe I have proven the bug with an expanded unit test.

I took these two test cases that used writeFragment, and added what I think is the typical workflow we are using with our mutations, namely readQuery then writeQuery and expecting a change. Both of my new tests fail to receive a change after writeQuery.

Two areas of concern:

  • my test addition is based on a big PR not-yet-merged #4261 (though this test addition is small)
  • I’m not confident enough that my new test code is explicitly correct - but I think it is.

Someone with more expertise, perhaps @jaydenseric, @hwillson or @benjamn please take a look at my reproduction PR and let me know if I have set the right expectations in the test https://github.com/apollographql/apollo-client/pull/4264

@hwillson that did not do the trick for me, sadly.

Was having the same issue described here (and in many other issues). I got things working for me by using client.watchQuery (simplified from actual implementation):

const MenuWrap = ({ client, children }) => {
  const [showMenu, setShowMenu] = useState(false) // reflects initial value for apollo state.showMenu
  client
    .watchQuery({ query: clientShowMenu })
    .subscribe(({ data: { showMenu } }) => setShowMenu(showMenu))

  return <div style={{ marginLeft: showMenu ? 300 : 0 }}>
    { children }
  </div>
}

// somewhereElse.js

const toggleMenu = client => {
  const { showMenu } = client.readQuery({ query: clientShowMenu })
  client.writeQuery({ query: clientShowMenu, data: { showMenu: !showMenu } })
}

I had to do this because my <Query /> implementation only got updated whenever the value I was changing (toggling a Boolean) switch back to the initial value 😞. The above snippet sucks though, I’m having to keep track of changes and update local component state 👎

@rosskevin I have seen your comments around a lot of issues dealing with <Query /> not updating properly. Maybe a dumb question… but is it supposed to be used as a container for hydrating other components with data from local state? Sure does seem like it should.

@jbaxleyiii Not sure what is a result of this: Do we need to call client.queryManager.broadcastQueries() or not? Because its definitely not working without it.

Some context: We are injecting an Apollo client to a React component, which will do the manual readFragment/writeFragment on each new message from websocket. So, we are not doing it in update method.

This is fixed on master!

I’m trying to do some work on this, so far I’ve gathered the following information as of today:

Summary of my research

I’ll see if I can expose this in current tests or add a test to reproduce. apollo-client is not my area of expertise so this is going to be a slog.


edit: and it was, I got lost down the rabbit hole of updating the build and getting ts to run on tests in #4261 but I am back to it now.

Same here in my question https://github.com/apollographql/apollo-client/issues/3905

writeQuery never update Query components. I had to call broadcastQueries() in order to force to update.

Happens with writeFragment too (pretty clear it is, but maybe it worth mention it)

@dotansimha can you create a reproduction of this?

You can see a problem with writeQuery in apollo-upload-examples. I updated the dependencies recently and after mutations uploads no longer appear in the list.

I think I’m having a similar issue - it’s only just appeared after reinstalling from npm, previous cache updates would cause react to re-render, but now, although apollo-cache IS being updated, these changes are not being flushed to react for whatever reason

apologies for not being more descriptive, here’s my package.json in case it helps:

    "dependencies": {
        "apollo-cache-inmemory": "1.3.7",
        "apollo-client": "2.4.4",
        "apollo-fetch": "0.7.0",
        "apollo-link": "1.2.3",
        "apollo-link-core": "0.5.4",
        "apollo-link-error": "1.1.1",
        "apollo-link-http": "1.5.5",
        "apollo-link-state": "0.4.2",
        "apollo-link-ws": "1.0.9",
        ...
        "react": "16.4.2",
        "react-apollo": "2.2.4",
    },

Thanks so much, @danilobuerger. You must be a MobX master in addition to GraphQL 👍

I was able to fix my issue by sending the full data object to the AuthorsPanel.

Given this, I also agree that this issue can be closed.

Hi @rosskevin, thanks for your efforts. I have a simple example that is still demonstrating this issue. Let’s not close it at this time.

Here’s my repo: https://github.com/nareshbhatia/graphql-bookstore To reproduce the issue please follow the instructions here: https://github.com/nareshbhatia/graphql-bookstore/issues/1

@savovs we use writeQuery because we don’t want to wait.

@rosskevin I have read the comments above. I am sharing what fixed it for us in case it helps someone else.

@SMJ93 please read the comments above. This is already confirmed NOT to be a react related issue, this is apollo-client or upstream from there. Please see the above research comment https://github.com/apollographql/apollo-client/issues/2415#issuecomment-431109153

We fixed the issue by changing some of our components that used the cached data from PureComponent’s to Component’s.

We recently upgraded react-native, react and react-apollo (and a lot of other libraries) so it looks like something changed in the way they do the prop comparison or the way the cache works.

Hope this helps.