-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v3] cache.modify with optimistic result does not broadcast change #6706
Comments
@martaver Can you put this code into a runnable reproduction using either this repo or this CodeSandbox? You seem to be using |
Hey @benjamn thanks, these are quite handy :D I'm trying to put together a repro here: https://codesandbox.io/s/dazzling-morse-dlg23?file=/src/App.js But I'm running up against a brick wall... I added a mutation to add a child person to a parent, and an update function to add the response to the parent's children. The field modifier doesn't run, either for the optimistic response or the response from the link. So obviously I've got something very wrong here... Also, when I try to check the contents of the cache, all the keys are there, but the values are all null. Am I missing something very obvious here? Sorry, it seems I'm much greener to GraphQL than I gave myself credit for, and I've had to eat a bit of humble pie :-/ |
The problem with all cached keys being null also exists in the vanilla repro CodeSandbox: https://codesandbox.io/s/divine-river-fggny?file=/src/App.js I'm not sure how to proceed now. I kind of need the cache working to be able to check myself in the repro. Or if it is working as intended, then I'm so confused. |
@martaver Ok, thanks very much for sharing (the beginnings of) a reproduction! We'll take a look, and hopefully either identify/fix the problem or clarify how things are supposed to work. |
@martaver I've been able to resolve the issue with the above CodeSandbox repros here. Press the Add friend button to run the mutation with an optimistic result. I see the optimistic result in the UI but there's a chance I didn't re-implement this as close to your use case above. If so, please feel free to modify it! |
Oh geez guys, I'm sorry, I gave you the wrong repro link... here's what I meant to send you: https://codesandbox.io/s/dazzling-morse-dlg23?file=/src/App.js Please note in it the schema, my use of the link to provide peopleData instead of the resolver in the query, and the fact that when I console.log the local cache, all values are indexed, but are null. @jcreighton thanks for your repro, but I think it might be side-stepping the issue that I'm trying to point out. Notice that you are returning In my case, I am trying to act on values that are returned from a link in response to AllPeople (check my repro and note that I'm not using resolver in my AllPeople query, instead I'm returning peopleData through the link). My understanding is that, based on the schema defined, apollo client should normalise the payload returned from the link and split it into independent people entries in the local cache. Those entries should contain a children property with refs to one-another as appropriate for their parent-child relationships. I know that only one side of that relationship will be indexed by apollo client, so I want to write an update function so that updates children when a new parent is set. For this I create an AddChild mutation, which you can trigger with the 'test' button. It's supposed to add a child person to Person with id '1'. Only neither the optimistic result nor the response from the link are correctly ingested by the cache. When I serialize the local cache to console.log, I see that there are entries for each Person, including the new child, but they are all null. I was hoping to be able to debug my problem by inspecting the cache... So I don't really know what's wrong here... Am I handling my query and mutation in the link incorrectly...? Is this a bug in apollo (unlikely, I hope...?) The end result I am looking for is that the child appears immediately underneath Person with id '1', optimistically, and then is updated with the result from the link. |
@martaver Thank you for the updated repro link! I've made some modifications and it's working, check it out: https://codesandbox.io/s/green-cdn-hef5f?file=/src/App.js These are the changes:
This was tricky to resolve and would've been easier to catch if |
@jcreighton Go for it (in a new PR please)! |
@jcreighton thanks for the update, this looks like its working fine :) Can I ask a few questions about your implementation? Why is writeFragment necessary? Shouldn't the optimistic result and then the query result automatically be normalised and added to the local cache? Or does using the update function replace the default cache behaviour in some way? Ideally, I would just like to leave apollo to work 'as normal', and simply be able to tweak the parent's children, leaving everything else as is. |
@martaver The reason |
Hi, Sorry for pressing this - I'm just really trying to understand the reasoning behind how this caching works, and there are things that aren't making sense for me. So I'm looking at @jcreighton 's solution here again: https://codesandbox.io/s/green-cdn-hef5f?file=/src/App.js and now So it looks like Also, I'm trying to use cache.modify as in this example in another app, also with an optimistic response. In my other app, the optimistic result does not render in the UI, even though the mutation result does. If I inspect the cache throughout all of this, I can see the optimistic record and actual record added to the cache. If I watch the parent's collection of children, both the optimistic record and the actual record are added to the list of children (the optimistic record being replaced by the actual one, correctly). However, in the UI, only the actual result renders - there is no render update for the optimistic result. One thing to note is that after cache.modify is done, the actual JSON object is added to the list of children, not a ref to it. I don't think that's related to the problem - but it was odd, at any rate - I kind of assumed that I could rely on apollo to keep anything with a __typename and id normalized for me. Anyway, finally I found the culprit causing my optimistic response to fail - a missing field in my optimisticResponse - which was returning from the api as This 100% I think any of these read/write errors should be, if they aren't already! |
@martaver I accidentally introduced that change when reproducing something else. I reverted it. |
Hi, okay... So I'm confused now... I'm assuming that apollo client has default behaviour for consuming payloads from mutations - where the payload is normalized and cached by typename and key. Does defining an update function circumvent that default behaviour? Is that why writeFragment is necessary? In that case - why did the example still work fine when writeFragment was removed? Is that because the whole object ends up added to the children array instead of just a reference? If that's not the case, and the default behaviour still happens - why do we need the writeFragment code? Shouldn't I just be able to look up the entry from the default behaviour and patch children? Ideal scenario would be to accept default behaviour without having to write a fragment, and simply patch children. Actually, the most ideal behaviour would be to be able to define a TypePolicy somehow that can automatically keep parent and children fields in sync. After all, these relational rules should be universal! |
Actually I figured I'd try the type policy approach. It would be hand if the cache knew how to update children on the parent automatically whenever the child's parent property was set. And vice versa. It seems that's not possible though because there's no way that I can get a reference to the present object being added when inside the field merge function for 'parent'. E.g.
Here's a reproduction: https://codesandbox.io/s/tender-mountain-hq3li?file=/src/index.js Am I missing something obvious here? Shouldn't I be able access the current object being merged? |
Closing this as the initial issue was resolved. |
I have a schema where a Taxonomy is a self referencing node, in a one-to-many parent child relationship:
The @hasInverse directive is dgraph-specific, and sets up a two-way relationship, that updated the inverse edge when one is modified.
I am attempting to optimistically add a Taxonomy node under a parent in the following mutation:
I want the UI to update optimistically, inserting a temporary object until the query is completed, so I specify a compatible optimistic result.
Apollo doesn't know anything about the @hasInverse directive, so I create options that provide an update function to modify the cache and keep the parent's children up-to-date in each case.
Both results (optimistic and actual) reach the update function. Both results are the same shape. Only the actual result from the query emits in a change in the query data shown in my UI. The temporary Taxonomy is nowhere to be seen.
I might be missing something, but it sure seems like a bug to me.
More, after I delete and add the node a few times in succession, eventually the add fails silently, and the result data from the add payload gets emitted to the UI as 'undefined'.
Not sure what's going on there...
Is AC3 still ironing out bugs with this kind of stuff?
The text was updated successfully, but these errors were encountered: