Apollo-client: After updating query data with subscribeToMore the query data in the component is empty

Created on 29 Sep 2018  路  8Comments  路  Source: apollographql/apollo-client

Intended outcome:
Update to apollo-cache-inmemory 1.3.0.

Actual outcome:
This below code no longer works as expected in the new version. The initial query is fine and I get the message data. When the subscribeToMore.updateQuery updates the query's cached messages data, the component re-renders with the data object being {}. I verified this only happens with version 1.3.0, and not with the previous version I was using (1.2.10). The strange part is that in the devTools the cached data looks correct, but when it gets to the component level it is empty.

messages({"max":10,"id":"123"}):
0:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).0
1:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).1
2:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).2
3:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).3
4:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).4
5:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).5
6:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).6
7:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).7
8:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).8
9:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).9
10:鈻綬OOT_QUERY.messages({"max":10,"id":"123"}).10 <-- This is from the subscribeToMore update

Problem code:

const createSubscriptionUpdater = (subscribeToMore, variables) => (
    () => subscribeToMore({
        document: MESSAGES_SUBSCRIPTION,
        variables,
        updateQuery: (prev, { subscriptionData }) => {
            const newMessages = subscriptionData.data.newMessages;

            return newMessages
                ? {
                    ...prev,
                    messages: [...prev.messages, ...newMessages]
                }
                : prev;
        }
    })
);

const Messages = ({ id }) => (
    <div>
        <Query query={MESSAGES_QUERY} variables={{ id }}>
            {
                ({ subscribeToMore, loading, error, data }) => {
                    if (loading) return <span>Loading....</span>;
                    if (error) {
                        console.error(error);
                        return <span>Error loading messages</span>;
                    }

                    return <MessageList onLoad={createSubscriptionUpdater(subscribeToMore, { roomId })} messages={data.messages} />;
                }
            }
        </Query>
    </div>
);

How to reproduce the issue:
Create a query to get initial data and use the subscribeToMore callback to update it's data from a graphql subscription.

Versions

  System:
    OS: macOS High Sierra 10.13.6
  Binaries:
    Node: 8.10.0 - ~/.nvm/versions/node/v8.10.0/bin/node
    Yarn: 1.7.0 - /usr/local/bin/yarn
    npm: 5.6.0 - ~/.nvm/versions/node/v8.10.0/bin/npm
  Browsers:
    Chrome: 69.0.3497.100
    Safari: 12.0
  npmPackages:
    apollo-boost: 0.1.16 => 0.1.16 
    apollo-cache-inmemory: 1.3.0 => 1.3.0 
    apollo-client: 2.4.2 => 2.4.2 
    apollo-link: 1.2.3 => 1.2.3 
    apollo-link-http: 1.5.5 => 1.5.5 
    apollo-link-state: 0.4.2 => 0.4.2 
    apollo-utilities: 1.0.21 => 1.0.21 
    react-apollo: 2.2.2 => 2.2.2 

Most helpful comment

@benjamn Sorry for the delayed response. I have updated to 1.3.5 and I no longer see the issue that I originally reported for subscriptions.

Thank you for the fix!

All 8 comments

I had a different bug with similar symptoms: the store content would update, but the component would render with outdated data. Something is amiss in the new caching behavior as introduced by #3394 - I tried to come up with a simple test-case but couldn't pinpoint it yet. For now, had to revert all projects to v1.2.x.

@cruzj6 Do you think you could put together a small runnable reproduction in the form of a github repository? Happy to look into this today, though downgrading apollo-cache-inmemory in the meantime is a good workaround.

For example, here's a React Apollo subscription example app that seems roughly similar to yours, but still works after I update apollo-cache-inmemory to version 1.3.0: https://github.com/rwieruch/fullstack-apollo-subscription-example/

If you can identify what's different between that example app and your app, that would be a great place to start. Maybe you could clone that app, and then update it to look more and more like your app, until it begins to exhibit the problem?

Please try the latest version of apollo-cache-inmemory (1.3.5) when you have a chance, since I believe 9d6995e407f9b8cc0fc6edbf7ea8d57af9b128ba will help with this issue:

npm install apollo-cache-inmemory@next

Specifically, that commit reverts a previous commit of mine that attempted to handle adding __typename fields without making a deep copy of the query document, but I missed some important edge cases. Accidentally requiring a __typename field where none was previously required can cause the query result to appear incomplete, which may result in React components re-rendering with an empty data object.

@cruzj6 Any chance to try the latest version?

Please try updating to [email protected] when you have the chance! This and other bugs should have been fixed by #3964.

@benjamn I tried 1.3.5 and my issue still remains. But I still don't have an isolated test-case, so there is a good chance my issue is somewhere in my code rather than upstream in here.

@benjamn Sorry for the delayed response. I have updated to 1.3.5 and I no longer see the issue that I originally reported for subscriptions.

Thank you for the fix!

Was this page helpful?
0 / 5 - 0 ratings