rossco555
rossco555

Reputation: 1

Vuejs - add property to each item in an array with reactivity

I have banged my head against all kinds of walls for days and would love some help with this please.

I am getting the following error but can't really see how what I'm doing has anything to do with vuex here: [vuex] do not mutate vuex store state outside mutation handlers.

In my vue component I define an empty array for future data I get from an external API.

data() {
   return {
      costCentres: [],
   };
},

I have a watch on my vuex store object named schedule (which I've brought in using MapState... and also tried with a getter using MapGetter to see if that made any difference). In this watch I create my array costCentres, with each element consisting of about five properties from the API. I add two properties at this point (sections and tasks) which I intend to later populate, and which I need to be reactive so I do so in accordance with the Vue reactivity documentation which all the other questions I've found remotely like mine seem to reference.

watch: {
        schedule() {
            if (this.schedule.rows) {

                this.costCentres = this.schedule.rows.filter((row) => {
                    return row.cells[
                        this.schedule.columnKeysByName["Cost Code"]
                    ].value; // returns row if Cost Code value exists
                });

                this.costCentres.forEach((costCentre) => {
                    this.$set(costCentre, 'section', null);
                    this.$set(costCentre, 'task', null);
                });

            }
        },

The this.$set lines throw the earlier mentioned error for every element in the array.

When I later update the properties, the change is reactive so its just the flood of error messages that's got me beat. Obviously if I don't use set then I don't get reactivity.

I have no idea how what I am doing is related to the vuex store as costCentre is a plain old data property.

I've tried hundreds of variations to get this all work (including this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) which doesn't seem to work) and I've run out of options so any assistance would be greatly appreciated!

(Please also let me know if I need to show more code - I was trying to keep this concise!)

Upvotes: 0

Views: 1425

Answers (1)

Michal Levý
Michal Levý

Reputation: 37793

  1. this.schedule.rows is an array containing some objects (mapped from Vuex so the array and objects inside "belongs" to Vuex)
  2. You are creating this.costCentres by filter - so in the end this.costCentres is just another array containing subset of objects from this.schedule.rows (elements inside are just pointers to objects inside Vuex)
  3. In the forEach loop, you are modifying objects which are part of the Vuex store and as a result getting error [vuex] do not mutate vuex store state outside mutation handlers.

If you want to modify those objects, only way is to use Vuex mutations

Alternative solution is to make a copy of objects (create new objects with same values):

this.costCentres = this.schedule.rows.filter((row) => {
    return row.cells[this.schedule.columnKeysByName["Cost Code"]].value;
  })
  .map((row) => ({...row, section: null, task: null }))

Note: code above creates just a shallow copy so if your objects does contain some deeply nested properties, you have to use some other way to clone them

Now objects inside this.costCentres are not part of the Vuex and can be modified freely without using mutations...

Upvotes: 2

Related Questions