I'm not 100% sure this is a bug, but whenever we use optimisticResponse on a mutation hook the UI will freeze for ~500-1000ms. Removing the optimisticResponse will render the UI updates without any lag -- the feedback is instant.
For example, a user selects an option from a dropdown and the dropdown will only close 500ms after they've selected. If we remove the optimisticResponse the dropdown closes immediately.
I was wondering if anyone's had this issue and if there's a workaround? We want to update the UI as the user selects an option but can't because of the lag.
Here's an example of of a mutation with an optmisticResponse that would delay an UI updates
updateUser({
variables: {
userID: user.id,
name: newName,
},
optimisticResponse: {
__typename: 'Mutation',
updateUser: {
...user,
name: newName,
},
},
update: updateUserCache,
})
--
"apollo-cache-inmemory": "^1.6.5",
"apollo-client": "^2.6.8",
"apollo-link": "^1.2.13",
"apollo-link-batch-http": "^1.2.13",
"apollo-link-context": "^1.0.19",
"apollo-link-error": "^1.1.12",
"apollo-link-http": "^1.5.16",
"apollo-link-ws": "^1.0.19",
"apollo-utilities": "^1.3.3",
"react": "^16.13.1",
"react-dom": "^16.13.1",
Can you share two performance profiles/flame graphs that show the time between the click and the finished rendering (with and without optimisticResponse)? Also, are you using shouldComponentUpdate or React.memo in a React subtree that renders data of a query that's affected by the updateUserCache function?
Yes, using useMemo to the affected cache updates. I added more and double checked the dep arrays to make sure it was ok.
Here are some graphs, looks like about 130ms for the optimistic cache update



The cache updates take much less time than the 500-1000 ms you mentioned above, so the performance problem may be caused by the re-rendering that's happening after the update.
The reason why I was asking about shouldComponentUpdate and React.memo is that the InMemoryCache returns a new JavaScript object for every object in the query result after an optimisticResponse is applied, even for objects that didn't change. Therefore, useMemo and other React performance optimizations that use === to compare query results don't work for optimistic responses (see issue #4141). Do you think this could be the reason for the UI freeze you are seeing?
I've been digging into this and I think it's because we have one large query that's a combination of a few queries and the single object gets quite large because of that. I'm starting to break it down into smaller queries and seeing if updating the cache will be improved this way. So when we write to the cache it updates a smaller portion.
The memo stuff had a small improvement, but not enough to solve the problem.
Thanks for all the help @klaussner. I'm going to keep digging into this and report back.
We were able to get around this through various changes to our app. The largest change was breaking down one massive query we had into lots of smaller queries. We should've done this in the beginning but were fairly new to GraphQL when we started.
By breaking down the cache into smaller pieces I'm guessing each update now only updates a small portion of the cache instead of a huge object.
We also doubled down on React.useMemo which seems to have helped with components that would receive updates but didn't need to re-render.
Lastly we trimmed down some views and tried our best to keep the DOM as light as possible.
With those three updates things are feeling a lot faster and we haven't run into massive lag issues.
Most helpful comment
We were able to get around this through various changes to our app. The largest change was breaking down one massive query we had into lots of smaller queries. We should've done this in the beginning but were fairly new to GraphQL when we started.
By breaking down the cache into smaller pieces I'm guessing each update now only updates a small portion of the cache instead of a huge object.
We also doubled down on React.useMemo which seems to have helped with components that would receive updates but didn't need to re-render.
Lastly we trimmed down some views and tried our best to keep the DOM as light as possible.
With those three updates things are feeling a lot faster and we haven't run into massive lag issues.