-
-
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
Patch to nested object is changing object content order #300
Comments
@trevorgeise Thanks for your issue. Problem 1:
Problem 2: |
Absolutely! This is how my module looks (slimmed down for clarity)
I expect the field changed to be updated in Vuex, which will trigger all computed properties that reference that field to re-run, but not computed properties referencing sibling fields. Then I expect just that field to be updated to Firestore. Then I expect no serverChange to trigger.
The field in Vuex gets updated, but the object the field lives in (page.notes) gets re-ordered. e.g. if the object pulled down from firebase looked like
if I updated the note1 text with the above action vuex looks like this:
At this point any computed property referencing any of the fields inside notes gets re-run, as if the entire object got recreated. Then a beat later a serverChange gets fired and the document reverts back to the proper order, with the updated field. Then all computed properties run again.
|
I'm still not sure why For your first problem. It seems to me that everything works as expected, all but the computed properties. In JavaScript you can never assume order in object props will always be the same, this might even differ between browsers as well. As for reactivity of computed properties based on certain ids, this is always very fragile in Vue 2 but it is a problem of how computed properties work, not my library. With some experience you'll learn what is possible and what is not reactivity-wise when it comes to computed properties. If you share the code of the computed properties you are referring to, maybe I can give extra advice. 😄 -- |
Actually, when iterating on an object, in modern browsers, the order of keys is supposed to stay in the same order as the order in which they were created, except for integer keys and symbol keys. I recently was suprised too to see in my app that I had an issue with order, but I didn't go to the bottom of it to know what was responsible. I'll check it shortly to know if it could come from the library. |
Yes, that's my understanding too @louisameline . I think in simplest terms my issue is this: But, If I use a mutation to make the change in Vuex, it works exactly as expected. Only the updated field triggers an update. Everything doesn't get re-calculated. I just tried hijacking the patch hook so instead of calling updateStore(doc), I mutate the store myself with Vue.set. This works great from a Vuex perspective. Everything updates properly, nothing is reactive that shouldn't be. Later today I will try to recreate the issue in a test repo. |
Alright, I think I found the issue. I kind of suck at digging through code, but I think when you are calling I think the reason that is happening is because when that merge happens, you may be doing something in merge_anything that causes the object to think the updated property is in fact a new property, and therefore, as @louisameline pointed out, the order changes because the creation date changes. Whatever the reason, this makes Vue see the whole thing as new, and triggers reactivity on the whole thing, rather than just the updated field. That causes everything touching the notes object to re-render, it thinks the whole notes object has been replaced and so everything needs to be updated. I think that is also why serverChange gets called. I'm guessing this merge thing isn't happening on the update to firstore. So in firestore only the field is getting updated, not the whole object. So when that comes back down the pipe, it sees a difference and has to reconcile. Instead of merging, here is what I did inside the patchHook to update just the target field.
That works great. Only text gets updated, the rest of the object is left alone. |
@trevorgeise Ah... I understand the problem now. I never realised this would trigger Vue's reactivity to see the entire object as new, but I guess it makes sense... I'm not sure how to get around this though. I feel like messing with this might break some things. I will definitely keep this in mind for version 2 though! I'm already making good progress on this. 😉 As for the serverChange hook triggered, maybe we can do a VSCode Live session so it's easy to try and debug on my end. Can you add me on discord? |
@trevorgeise I implemented your fix for For problem 1 I kind of want to wait for v2... (your fix on your branch was really a lot of lines and added new dependencies) I'm working on v2.0 now, and I'll make sure to have a test that covers and prevents this case!!! |
I have exactly the same issue at the moment—a component bound to one part of the data is being triggered to re-render when other unrelated data is changed. I also tried vuex-firestore, but have the same problem there. Replacing whole Vuex objects is definitely going to lead to performance issues in Vue reactivity, so I'm really glad to hear this fix is on the cards. Do you have any idea of a timeline yet? |
I fixed it in this branch, https://github.com/trevorgeise/vuex-easy-firestore , if you want to see a solution. |
Thanks—I will definitely take a look. Are you planning to maintain a fork, or is @mesqueeb going to roll it back in? |
I'm not sure yet. Probably as my needs require. But @mesqueeb is planning on implementing a proper fix for 2.0, so hopefully I can just switch to that. |
Thanks, based on @trevorgeise's version, I wrote a fix, but when I tried adding the fix, it broke a bunch of tests, so I have some more troubleshooting to do. I ran out of time today, but will try to continue working on this over the next days. |
@trevorgeise @dsl101 @trevorgeise Both your problems should now be fixed!🎉 -- |
I have a case where there's still an unwanted update / re-render in Vue. I have an object bound to a set of users in firestore at
In my code, I bind a component to, say, all the user names. If I change that field in firestore console, I see my component update, and also see the If I change But, if I delete the |
@dsl101 i will do extra troubleshooting for deleting props. But you can just set the prop to This workaround would solve your issues I think. |
Not sure I understand the workaround—changes are coming in to my app from
elsewhere via firestore... Where would I intercept the update?
…On Thu, 23 Apr 2020 at 21:26, Luca Ban ***@***.***> wrote:
Reopened #300 <#300>
.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#300 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAG33PRV6WXMHDCUIRRVJYDROCP7XANCNFSM4LCP7O2A>
.
|
@dsl101 wherever you're deleting the property. Can't you set it to |
Ah, I see. Yes, I'm converting this app from firebase to firestore, and setting the key to It would obviously be great if a delete really did only delete the key, but much less of an issue in the short term now. Many thanks for the updates! |
Just an update on this—adding properties is also triggering an update on the bound Vue component. So whilst setting unwanted props to |
@dsl101 I'll have to double check my logic for adding props that were not already there, and for deleting props as well. in the meantime, if you want to try your hand, it's this logic that would need updating: Anything inside this |
OK. I've been able to reproduce the 'error' (if we can call it that for now—also likely my misunderstanding of Vuex :) in a pure Vuex store, so I'm going to try submitting an issue to Vuex and see if this is expected behaviour. The premise is this: State contains a single object with 1 property ( There are also 3 other mutations to create, increment, and delete a second prop ( |
I have some nested data coming in from Firestore, so that my store looks like this
I'm running into two problems with this, and I think they are related.
Problem 1
When I update the text on a note, using patch, the order of my notes (the position of the key/value pair, nothing to do with the order field) inside my notes object changes, which seems to trigger reactivity on the whole object, causing everything connected to page.notes to rerun ( all notes). This happens instantly based on the changes made in the store, not from data coming back from Firestore.
I've verified this by both logging out the object at each point, but also by having a v-for of notes fed by the object. When the patch happens, the updated note jumps to the bottom of the list in the ui.
If, instead of going through vuex-easy-firestore I update the store myself with a mutation, either by using
Vue.set(state[pageid].notes[noteid], 'text', newText)
or withstate[pageid].notes[noteid].text = newText
, all reactivity happens as expected. The store gets updated, the object doesn't change order, and only the computed properties touching the note text get re-run.Problem 2
Second problem is after every patch serverChange gets fired. I'm assuming this is because the nested object in the store is a weird order, but the object coming back from firebase is in the original order, so it fails the diff. However, serverChange seems to get triggered even if I update a non-nested field, like page.title.
Any thoughts would be greatly appreciated!
The text was updated successfully, but these errors were encountered: