React-Apollo Store update not triggering UI update
[SOLVED] Scroll to the bottom!
I am consistently having the issue where in some cases when I update the Apollo Cache/Store the UI is auto-magically updated and in other cases the UI doesn't seem to be affected by the change. It depends on what type of change I'm making to the data.
If I make API calls to do a DELETE
mutation, and on success I update the apollo store by plucking the item from the array and calling store.writeQuery
, the UI auto-magically gets updated and it's great!
On the other hand whenever I do an ADD
mutation, and on success I update the apollo store by pushing the newly created item into the array and calling store.writeQuery
, the UI is unaffected.
Let me show you the code
Here is my code for deleting an review:
And here's my code for adding a review:
As you can see the code is identical outside of how I modify the collection of reviews. In one case I delete an item, in the other I push a new one. Yet their impact on the page is very different. I'm following the examples from the update documentation.
One piece of feedback I got was that the writeQuery has issues if the data your adding/editing doesn't match what's already in the store. So I logged an existing item versus the new item being added and here are the results.
As you can see they're identical. So I'm not sure what's up!?
I console.log('newReview', newReview)
and here's what I get:
If I console.log
the localStoreData
after updating it I see the following. You can see that the new review was added to the collection. And that's what I'm passing to the writeQuery
, so what gives?
This is infuriating! Is it a bug? Am I doing something wrong? I'm having trouble getting answers.
My Workarounds
Initially I was getting around this by triggering a page refresh, which is gross and I don't want to go that route.
I did find another trick which was to add a refetchQueries
property to my mutation call. This tells Apollo that the data has changed on the server and it needs to re-call the API to fetch the updated data. This isn't the worst thing every but it does seem silly to hit the server when I have all of the info on the client to update the store.
If you know what I'm doing wrong please drop me a line in the comments below or on twitter @coreysnyder. This is driving me nuts!
SOLVED!
Thanks to the help of Lawrence Baker, from Spectrum Chat, who pointed me in the right direction; This is case closed! He pointed out that there was a nuance between my delete code and my add/edit code in that with the delete I was creating an entirely new object versus modifying the existing one. When you modify the existing object in memory, when Apollo does an equality check between the new/old state, it sees the two objects as the same object, and therefor does not trigger an update.
I tested this by first doing: localStoreData.getProductReviews = [...localStoreData.getProductReviews, newReview]
This didn't work because I was still modifying the base localStoreData
object, even though I was creating an entirely new getProductReviews
array.
So I with a level further with:localStoreData = { getProductReviews: [...localStoreData.getProductReviews, newReview] }
In this case I am creating an entirely new localStoreData
object and therefor Apollo sees it as a new state and triggers the updates to my UI.
I'm so glad to have solved this because it was driving me nuts! I am going to circle back and retrofit my old code using this new revelation.