Slawomir
Slawomir

Reputation: 3343

Dynamically creating a reactive array in the Vuex's state

My component would like to add a new reactive-array field to the SST (vuex). I tried in beforeCreate hook, but the added array is not reactive; it's just a plain JS array.

Note that this is not the same as adding/removing elements from an existing array created at the Vue's initialization time. Such arrays are "wrapped" and become reactive as expected, mindful of "Array Change Detection" gotchas.

In my case, I'm trying to dynamically add an entirely new field of array type to the SST and make it reactive at the same time. Possible?

Upvotes: 9

Views: 7778

Answers (3)

acdcjunior
acdcjunior

Reputation: 135762

Have a look at Reactivity in Depth - Change Detection Caveats:

Change Detection Caveats

Due to the limitations of modern JavaScript, Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.

But you say you are adding an array dynamically:

I'm trying to dynamically add an entirely new field of array type to the SST and make it reactive at the same time. Possible?

From the docs (bold is mine):

Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the Vue.set(object, key, value) method:

Vue.set(vm.someObject, 'myArrayName', [1,2,3]);

Which should help you making your array reactive.

Upvotes: 7

Piotr Żak
Piotr Żak

Reputation: 2413

I see two problems here:

  1. add dynamically array using vuex.
  2. add dynamically element to this array and render this element.

I've initiate array if not exist in add method because when I'm receiving data from server myArray is not exist.

My solutuion below:

myVuexArray.js

import Vue from 'vue'

const state = {
  myObject: {
    myArray: [],
  }
}

const getters = {
  getMyArray: state => {
    return state.myObject.myArray;
  }
}

const mutations = {
  addElementToArray(state, value) {
    if (state.myObject.myArray === null || state.myObject.myArray === undefined || state.myObject.myArray === '') {
      // initiate array
      state.myObject.myArray = [];
    }
    // add new element to array
    Vue.set(
        state.myObject.myArray,
        state.myObject.myArray.length,
        value
    );

    // creates a new array everytime this solves the reactivity issue
    Vue.set(state, 'myObject.myArray', state.myObject.myArray);

    return state.myObject.myArray;
  },
  removeElementFromArray(state, index) {
    state.myObject.myArray.splice(index, 1);
  }
}

export default {
  state,
  mutations,
  getters
}

Best regards

Upvotes: 1

Guillaume Meral
Guillaume Meral

Reputation: 462

Dynamic module registration could help you to achieve this : https://vuex.vuejs.org/en/modules.html

This would allow you to dynamically register a new module containing your array field in the beforeCreate hook.

Upvotes: 0

Related Questions