Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

1.9K
Views
Vuex, update property of object in array causes many mutation methods

Let's say you have a store like this. And a component where you select a car from the list which gets passed as a prop to another component where you can edit various properties of the car object.

If the car objects had more properties like brand, weight etc. I would have to either:

  • Create a new mutation for every property This has the downside of causing a huge amount of mutations, which will make the store file very unreadable in my opinion.

  • Create a generic mutation that takes an object, a field, and a value and assign that. This has the benefit of only having one generic mutation. But it has the downside that it can't handle nested objects.

  • Create a new car object in the component and replace that in the state by id field. This feels like a clean solution but it would involve copying the object to remove mutability, and that feels less clean. And also slow down the app if use a lot I guess.

In my projects, I've ended up with a mix of these options which just feels chaotic.

So, my question is if there's a better pattern to use than any of these? And if not, which is considered the best practice. I've searched for an answer to this for a long time but never found any good explanation.

state: {
    cars: [
        {id: 1, color: "blue"},
        {id: 2, color: "blue"},
        {id: 3, color: "blue"},
    ]
},
mutations: {
    setColor(state, {car, color}){
        car.color = color;
    }
},
getters: {
    allCars(state){
        return state.cars;
    }
},
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

I would do it using deepMerge function:

export const mutations = {
  setCarProperties(state, car) {
    const index = state.cars.findIndex((item) => item.id === car.id);

    Vue.set(state.cars, index, deepMerge(state.cars[index], car));
  }
};

So you can change and add properties (even nested):

updateCarType() {
  const car = {
    id: 2,
    type: {
      engine: "electric",
    },
  };
  this.$store.commit("setCarProperties", car);
},

Please note I am using Vue.set in mutation. You may wonder why I don't change state like usually we do:

state.cars[index] = deepMerge(state.cars[index], car));

But that won't be reactive, so Vue.set is needed. https://vuejs.org/v2/api/#Vue-set

Check demo: https://codesandbox.io/s/questions-69864025-vuex-update-property-of-object-in-array-causes-many-mutation-methods-sq09z?file=/pages/index.vue

over 4 years ago · Santiago Trujillo Report

0

I will share my views on this subject. Sincerely I don't know the best practice, and there are a handful of variations of the same approach.

Basically, it applies only the second principle you mentioned, and keeps the reactivity in place for the whole update cycle.

In the store make a generic mutation:

mutations: {
    setItem(state, item) {
      let idx = state.items.findIndex((i) => i.id === item.id);
      Vue.set(state.items, idx, item);
    }
}

In component map the state items to a computed property, and make another one for the edited item:

computed: {
    ...mapGetters({ allItems: "allItems" }),
    localItem: {
      get() {
        return this.allItems[0];
      },
      set(val) {
        this.setItem(val);
      },
    },
},
methods: {
    ...mapMutations(["setItem"])
}

And the tricky part, update the local item:

methods: {
    ...mapMutations(["setItem"]),
    changeItem() {
      this.$set(this, "localItem", { ...this.localItem, color: "red" });
    },
}

Do not update directly object properties but rather assign the whole object, so that the computed setter is triggered and changes are committed to store, without any warnings.

Codesandbox

over 4 years ago · Santiago Trujillo Report

0

You can pass whole car object, with changed properties, to action:

async carUpdate({ commit }, car) {
  await // some axios or fetch call...
  commit('updateCar', car);
},

then commit mutation like:

updateCar(state, car) {
  state.cars = [
    ...state.cars.map((item) =>
      item.id !== car.id
        ? item
        : {
            ...item,
            ...car,
          }
    ),
  ];
},
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!