davestewart / vuex-pathify

Vue / Vuex plugin providing a unified path syntax to Vuex stores
https://davestewart.github.io/vuex-pathify
MIT License
1.37k stars 57 forks source link

component helper sync() does not trigger action/mutation subscription when value modified in a v-for loop #54

Closed Zireael closed 5 years ago

Zireael commented 5 years ago

Hi, code demo here: https://codesandbox.io/s/7m431nm7q0 (deploy: https://csb-7m431nm7q0.netlify.com/)

When I use computed property with sync() and then modify some value in an input field that is contained inside a v-for loop, the change gets committed to vuex, however it seems to be done directly, rather than through action/mutation. When doing the same but outside v-for loop, changes get committed the expected way through action/mutation.

It is a bit problematic, because: 1) I wanted to use a vuex watcher subscription that reacts to Pathify modifying data in store. Use case: beam the store change into server (let Pathify do it's magic with store, let me handle server requests on the side when I need to) 2) Changes bypassing action/mutation don't get picked up by my persisted state plugin (vuex-persist), and therefore don't get committed into local storage cache

Now, I could write my own actions/mutations but this would defeat the purpose of using Pathify, and also some data in my store is dynamically generated, so having Pathify make() is a godsend.

I saw in your documentation that I can make my own custom action/mutation like so: sync('items|update') but when I tried to write one, nothing is happening - no error no nothing. Should I put the update in store or inside component, how should it look like? Could you give a working example for this?

Thanks in advance for advice!

davestewart commented 5 years ago

Hey there,

Thanks for building a demo - it always helps!

OK, I think this is probably just a slight misunderstanding how how sync works.

When you sync the store sub-property to a component computed property, you should ONLY target the compound computed getter/setter (created by sync) using v-model. The set() handler function created by sync() has the code to commit() the mutation.

If you do what you did, you first target the get() portion of the compound property which returns the entire three object, then you target the sub-properties by reference – so it "jumps over" the setter function handling the mutation, and gets and sets the value directly:

  this is the getter
      and setter
          |
          v
one.two.three.a.counter
          ^        ^
          |        |
     you access    |
     the getter    |
                   |
          then bind the v-model
           to the sub-property

If you set strict: true in Vuex you will see that it complains.

So actually the loop has nothing to do with it!

Take a look at this demo:

I attempted to do the same thing as you in a loop, using the props ['a', 'b'] but couldn't seem to dynamically bind to v-model. I tried a few things like $options.computed[prop] but no luck, so I hardcoded a and b.

Make sense?

Sorry - Pathify is fairly abstract, so its's understandable that you might think to do this.

I do have a go at explaining how sub-property access works here but I'm also conscious that I don't want to overwhelm people with technical detail.

Zireael commented 5 years ago

Thank you for explanation. I fixed it like this: https://codesandbox.io/s/80jkqmvz8

My issue was that part of my object path was dynamically changing from prop passed from parent component. Now I'm declaring the computed properties at beforeCreate() and spreading ...(sync) to create computed properties right at the end of object path - thus they are reactive in input v-model

davestewart commented 5 years ago

Yep, that's the way to do it!