-
Notifications
You must be signed in to change notification settings - Fork 28
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
Cache went stale and wasn't recreated #157
Comments
The error happens when I leave the index page and on the new page cashay queries new data from the server. |
Ok, starting to understand:
What I'm still struggling with is how, if the maps-index response is flushed, does the maps-index component continue to render. For example if I:
|
Getting closer (without mutation handlers this time): When the user visits maps index, cashay stores the result and entities in redux, e.g.:
cashay also caches a "response" object in memory, which, as far as i can tell at this point, is the denormalized result of the query, be it from the server, or from redux (or both i suppose in some cases). So long as this "response" object exists, cashay will not ask redux, much less the server for an update. This is why mutationHandlers are necessary when there is a "response" object" in memory for a particular query. When my user clicks a specific Map, they are taken to a detail page that executes a new "map-detail" query. As part of this operation, cashay flushes the above-mentioned response object for the maps-index operation. Then let's say the user executes an update mutation to change the name of the map. Cashay updates redux so it looks something like:
When the user navigates back to the maps index page, cashay flushes the response for the map-detail query. Cashay also sees that it no longer has a response object for the maps-index query. So it presumably checks redux for an existing result. And it finds one! So it pieces together a new response, but entirely from local state (redux). Because cashay updated Here's where it breaks downThen the user clicks the same map and is taken back to the detail page. Cashay sees no "response" object for map-detail (it was flushed), but is able to piece together a new response from redux. Because no server query is required, the maps-index response object is not flushed! The user changes the name again. Cashay executes a mutation. The user navigates back to the index and doesn't see the change! This is because cashay found that the response object for maps-index was still there and used that instead of checking redux. How do we force flush a response when the user leaves the maps-index page but has not triggered a new server query? Another way it breaks downThen the user access yet another map which again flushes the response for the maps-index query. Then, the user clicks a big 'ol PLUS icon in the navbar to add a new map. Then the user fills out a new map name and mutation is executed. There are now 4 maps on the server. The user navigates back to the maps index page, but sees just 3 maps! This is because cashay, again, saw that there was no longer a denormalized response for the maps query, but there is still a result entry for the query. But that value (still) looks like this:
Still 3 maps. How do we update the @mattkrick i think this issue is ready for your eyes. This last comment I think summarizes the problem pretty well, but see above for more context. |
Side note: ☝️ I suspect that this problem goes away when |
there's a lot to dig into & i'm not sure i grok it all, but if stale data is getting to the view layer, then it has more to do with the ember integration i think. you shouldn't ever have to manually flush a result because the result will change whenever a mutation occurs as long as there is a mutation handler. |
tl;dr,
- when data comes back from the server, cashay normalizes it and stores in redux
- cashay also stores a denormalized response on the singleton itself in cashay.cachedResponses
- cashay prefers the denormalized response if it exists
- when another query affects the data involved in any denormalized response, the response is flushed
- on a subsequent request for the original query, cashay will piece together a new denormalized response using normalized result data it has stored in redux
- responses can be modified by the user via mutationHandlers if they so desire
This is how everything works great with a mutation handler:
- If my original query is for a list of things
- I navigate to a create thing page which executes a createThing mutation, I need a mutation handler to update the original list of things denormalized response (adding my new thing to it)
- going back to the index page is great, new thing shows up in list
Continuing, this is how it can break down:
- I now navigate to a *different* thing detail page which executes a new server query and simultaneously flushes the index denormalized response
- I navigate again to the create thing page which executes a createThing mutation, this time throwing an error because the mutation handler tried to modify a response that has been flushed
…Sent from my iPhone
On Jan 11, 2017, at 5:01 AM, Matt Krick ***@***.***> wrote:
there's a lot to dig into & i'm not sure i grok it all, but if stale data is getting to the view layer, then it has more to do with the ember integration i think. you shouldn't ever have to manually flush a result because the result will change whenever a mutation occurs as long as there is a mutation handler.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@mattkrick there may very well be some nuance at play with the Ember view layer, but I think there is a real bug here, and I think the reason you may not have run across it as much or at all in the action project is because your use of |
I'm not sure where this is breaking down either in Cashay or in my own code; but here's the reproducible scenario:
Note: I typed this up by hand (no copy+paste) so if there's some stupid syntax error its probably just a typo in this GH issue alone.
The SETUP
Two routes:
/maps
/maps/:map_id
Starting with the second route: a detail page that can create and update maps. Creating is done by clicking "NEW" on the index page, which triggers an action that generates a UUID, sets a
isCreatingNewMap
flag in redux state, and redirects to the detail page.The detail page has two queries and two mutations.
The two mutations are
createMap
andupdateMap
The queries are identical except one has
@cached
and is used when the map is being created. This is so thecreateMap
mutation knows to grab subfields.This is the relevant piece of the
MapDetail
component:Back to the index page, this is the relevant piece of the
MapsIndex
component:The SCENARIO
Part 1 (The happy version)
Step 1 - User visits index
Cashay fires a server query:
All maps are displayed with their name
Step 2 - User clicks "NEW"
And is taken to a detail page with a freshly minted UUID in the URL
No server request. Cashay executes
cachedMapQuery
shown in the component code above.Step 3 - User fills in name, triggers Save
Cashay executes a mutation:
map-detail
optimistic mutation handler fires!maps-index
optimistic mutation handler fires!then sends a server request
Step 4 - User navigates back to index
As part of this transition away, the detail route dispatches to turn off
isCreatingNewMap
. This triggers a redux subscribe callback. TheMapDetail
component, which has not been torn down yet, runsstateToComputed
one more time which triggers a cashay.query, but this time usingmapQuery
instead ofcachedMapQuery
(shown in the component code above). This triggers a (unnecessary?) server request:The transition completes and the user is now on the index page. The new map appears under the rest with its name. Everyone is happy so far.
Step 5 - User clicks the new map going back to its detail page
As in step 4, the map is looked up using
mapQuery
(the one without@cached
). No new server queries—presumably because of the side-effect query in step 4, Cashay must be using the cache from that query.Step 6 - User edits the name of the map and triggers save
map-detail
optimistic mutation handler fires!maps-index
optimistic mutation handler fires!And Cashay kicks off a mutation request to the server:
Step 7 - User navigates back to the index page
No new server queries. The maps new name appears as it should.
Part 2 (The sad version)
The difference here is we'll be editing an existing map's name, instead of creating a new map and then editing it.
Step 1 - User visits index page
Cashay fires a server query:
All maps are displayed with their name
Step 2 - User clicks an existing map and taken to detail page
Cashay executes
mapQuery
in the component as shown in the component code above:Step 3 - User edits the map's name and triggers Save
map-detail
optimistic mutation handler fires!maps-index
optimistic mutation handler throws error!The text was updated successfully, but these errors were encountered: