aulia amirullah
aulia amirullah

Reputation: 196

Why is state not updating in vuex?

I'm using vuex with axios to fetch data from the backend. It shows the updated state when I console-log the state. However, there is always no data when I call the state. Is there something I've missed?

vuex file

import axios from "axios"; 
import { uid } from "quasar";

const state = {
  data: {},
};

const mutations = { 
  addData(state, payload) {
    state.data[payload.id] = payload.data;
    console.log(state.data); //the data exist
  },
};



 const actions = {
      readData({ commit }) {
        axios({
          method: "get",
          url:
            "https://dev.activate.vi9e.com/api/purchase/receivegoods/index?action=list",
          headers: {
            "Content-Type": "application/json",
          },
        })
          .then((response) => {
            for (var i = 0; i < response.data.length - 1; i++) {
              let dataId = uid();
              let payload = {
                id: dataId,
                data: response.data[i],
              };
              commit("addData", payload);
            }
          })
          .catch((error) => {
            //handle error
            console.log("error message: ", error.message);
          });
      },
    };

const getters = {
  data: (state) => {
    return state.data;
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters,
};

Here is my template:

<template>
  <p>{{ data }}</p>
</template>

<script>
import { mapGetters, mapActions } from "vuex";

export default {
  methods: {
    ...mapActions("incominggoods", ["readData"]),
  },
  computed: {
    ...mapGetters("incominggoods", ["data"]),
  },
  mounted() {
    this.readData();
  }

};
</script>

Even though, I get the data whenever I console-log in mutations, the data in state is not updating at all. How can I fix this?

SOLUTION Thanks for all the comments. They are all worth problem-solving. The problem is due to the vue's reactivity. Vue seemingly doesn't allow handling the "object" (non-primitive data type) and not allowing the object is assigned by the array assignment way to handle the "Object". This is what I did based on the comments:

  1. I manipulated the data that I received from the backend manually (in which it has the "object data type" (non-primitive data type) and changed it to "Object data type").

In actions (within then(response))

for (var i = 0; i < response.data.length; i++) {
          let dataId = uid();

         // manipulate the "object" to "Object"
          let data = {
            poid: response.data[i].purchase_order_id,
            podate: response.data[i].po_date,
            vendor: response.data[i].vendor_name,
            qty: "0%",
            total_qty_ordered: response.data[i].total_qty_ordered,
            total_qty_receivable: response.data[i].total_qty_receivable,
            total_qty_received: response.data[i].total_qty_received,
            status: response.data[i].status,
            barcode: response.data[i].purchase_order_id,
            printed_id: response.data[i].printed_id,
          };
// END OF THE MANIPULATION 

          let payload = {
            id: dataId,
            data: data,
          };
          commit("addData", payload);

In mutations

addData(state, payload) {
    Vue.set(state.data, payload.id, payload.data);
  },

Upvotes: 0

Views: 1874

Answers (2)

slauth
slauth

Reputation: 3178

Vue's reactivity system cannot detect object property addition, see Reactivity in Depth.

In your mutation, change this

state.data[payload.id] = payload.data;

to this:

Vue.set(state.data, payload.id, payload.data);

Upvotes: 0

dili021
dili021

Reputation: 78

JS reactivity is a bit weird with non-primitive types (objects and arrays, object in further reading). Imagine an object as a bus with tinted windows. If a passenger (item in an array or key/value in an object) or passengers go in or out of the bus and you were looking at it from the street, you'd have no idea that something changed, the bus still looks the same. That's basically how it works, and you have 2 options for object reactivity.

You can either:

a) replace the whole object

b) in the case of Vue, use Vue.set (for actual objects, not for arrays)

Option a) looks like this:

// for objects
const addObjectProperty = (state, property) => {
  state.object = {...state.object, property)
}
// for arrays
const addArrayItem = (state, item) => {
  state.array = [...state.array, item]
}

What this is doing, is creating a new object on the fly using object literal syntax (the { } or [ ]). So this way, Vue is looking at your state.object, and see it's replaced with a whole new one and reacts accordingly.

Option b) looks like this:

const addObjectProperty = (state, property) => {
  // Vue.set params: object, key, value 
  Vue.set(state.object, state.object[property], property)
}

As for arrays, just use array methods, and don't manually change values like arr[x] = 10 as that will cause the same issue.

EDIT: If you have a nested object as a state property, you still have to replace the top-level object.

state: {
  this: {},
  is: {},
  what: {},
  you: {},
  need: {},
  to: {},
  change: {},
  not: {
    this: {}
  }
}
}

The easiest way to go about this if you have lots of nested state is by using vuex modules

Upvotes: 1

Related Questions