mrichar1 / jsonapi-vuex

Use a JSONAPI api with a Vuex store, with data restructuring/normalization.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Do not mutate vuex store for list of documents

jbmolle opened this issue · comments

Hi,
We have a small problem with the library.
In our project we try to get a list of Job Offers from a JSON API backend.
So we created a computed property:
jobofffers = this.$store.getters'jv/get'

And in the template we list all Job Offers with p(v-for="(offer, key) in joboffers")

But then we get an error on the page: "Do not mutate vuex store state outside mutation handlers".

We looked at it and here what we've found so far:

  • get calls checkAndFollowRelationships
  • checkAndFollowRelationships calls followRelationships for each record of the list
  • followRelationships calls addJvHelpers
  • addJvHelpers calls Object.assign which seems to trigger the vuex error

We also tried to use utils.deepCopy to avoid triggering the vuex error but that does not work.
We did the following:

  • let offers = this.$store.getters'jv/get'
  • joboffers = utils.deepCopy(offers)
    And then we get the error cannot convert undefined or null object because on a list, the _jv tag is under each element but not on the list itself.

How would you solve that?
Thanks,
JB

Thanks for reporting this issue!

I've had a brief look and I can't seem to replicate this issue. In the testapp in `examples/ we have a very similar code, which I have modified to be the following for testing:

computed: {
    all() {
      return this.$store.getters['jv/get']()
    }
}

<div v-for="(widget, id, index) in all" :key="index">
<div>{{ id }} {{ widget }}</div>
</div>

This doesn't return any errors.

Can you double-check that you are not using joboffers anywhere else in your code, or modifying offer or key in the template? If you are then using utils.deepCopy should work - in the testapp we do this to bind and modify data (for patching) for precisely this reason:

widget1() {
      return utils.deepCopy(this.$store.getters['jv/get']('widget/1'))
    }

Hi Matthew,

Thanks for your answer!
I've check again with the testapp and you're right, it's working fine.
I looked again at our code and I think I've found where the problem lies.
We're using Nuxt.js and if we call the store dispatch from asyncData() as we're doing then we got the error. If we call the dispatch from created() like in the testapp, everything works fine.
So the problem is with Nuxt.js. I'll keep digging to find why exactly.

Thanks again for the great library!

Hi @mrichar1

I think I have found why we have the bug on Nuxt.js.

In Nuxt.js asyncData, when we call the dispatch('jv/get', 'joboffers'), the library gets the Job Offers from the API.
The library calls the get function from actions, which calls checkAndFollowRelationships -> followRelationships -> addJvHelpers
addJvHelpers will add the isRel and isAttr functions to the elements in the store.

Then the store data are passed on the client side.
When we use a computed property this.$store.getters'jv/get' on the client side (browser), the get function from getters calls checkAndFollowRelationships -> followRelationships -> addJvHelpers.
But this time addJvHelpers works on store data that already have isRel and isAttr functions and by redefining them we trigger the "Do not mutate vuex store state outside mutation handlers" error.

By checking if isRel and isAttr are already present we can avoid the error.
I'm going to create a PR and you let me know if it's fine.