You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Vuex通过表单更新对象数据无效果,求排查与解决方法

Vuex Form Update Not Reflecting in State - Fixes & Explanation

Problem Statement

I'm trying to update a category object via a form using Vuex. When I click the Update button, the console logs the modified category data correctly, but the categories array in my Vuex state doesn't update at all. Here's my code:

Store Code

const state = { categories: [] };
//mutations:
[mutationType.UPDATE_CATEGORY] (state, id, category) {
  const record = state.categories.find(element => element.id === id);
  state.categories[record] = category;
}
//actions:
updateCategory({commit}, id, category) {
  categoriesApi.updateCategory(id, category).then((response) => {
    commit(mutationType.UPDATE_CATEGORY, id, response);
    router.push({name: 'categories'});
  })
}

Vue Component Template

<form>
  <div class="form-group">
    <label for="Name">Name</label>
    <input type="text" class="form-control form-control-sm" name="name" v-model.lazy="category.name" required>
  </div>
  <div class="form-group">
    <label for="Slug">Slug</label>
    <input type="text" class="form-control form-control-sm" name="slug" v-model.lazy="category.slug" required>
  </div>
  <div class="form-group">
    <label for="Avatar">Avatar</label>
    <input type="text" class="form-control form-control-sm" name="avatar" v-model.lazy="category.avatar" required>
  </div>
  <div class="form-group">
    <label for="Description">Description</label>
    <textarea type="text" class="form-control form-control-sm" rows="5" name="description" v-model.lazy="category.description"></textarea>
  </div>
  <div class="form-group">
    <button type="submit" @click.prevent="updateCategory" class="btn btn-outline btn-sm">Update</button>
  </div>
</form>

Vue Component Script

export default {
  data() {
    return {
      category: {}
    }
  },
  methods: {
    getCategoryById(id) {
      axios.get(`categories/${id}`)
        .then(response => {
          this.category = response.data;
        })
        .catch(error => {
          console.log(error);
        })
    },
    // Using mutation.
    updateCategory() {
      this.$store.dispatch('updateCategory', this.$route.params.id, this.category);
      console.log(this.category); //Display exactly data changed.
    }
  },
  created() {
    this.getCategoryById(this.$route.params.id);
  }
}

Root Causes

There are two critical issues preventing your state from updating:

  1. Incorrect Parameter Passing in Vuex Actions/Mutations
    Vuex actions and mutations only accept a maximum of two parameters:
  • For mutations: first is state, second is a single payload (you can't pass multiple separate arguments)
  • For actions: first is the context object, second is a single payload

Right now, you're dispatching with three arguments ('updateCategory', id, category), but the action will only receive id as the payload—category gets dropped entirely. The same happens when you commit the mutation: the third argument (response) is ignored, so your mutation never gets the updated category data.

  1. Broken Array Update Logic in Mutation
    You correctly find the matching record using find(), but then you try to update the array with state.categories[record] = category. This doesn't work because record is the object itself, not its index in the array. Vue can't locate the position to update, so the state remains unchanged.

Additionally, we need to make sure the update triggers Vue's reactivity system properly.


Step-by-Step Fixes

1. Refactor Action/Mutation to Use a Payload Object

Pack all your data into a single payload object to pass between components, actions, and mutations:

Updated Store Action

updateCategory({commit}, payload) {
  categoriesApi.updateCategory(payload.id, payload.category).then((response) => {
    // Pass id and the updated category as a payload object
    commit(mutationType.UPDATE_CATEGORY, {
      id: payload.id,
      updatedCategory: response
    });
    router.push({name: 'categories'});
  })
}

Updated Store Mutation

[mutationType.UPDATE_CATEGORY] (state, payload) {
  // Find the INDEX of the matching category
  const categoryIndex = state.categories.findIndex(element => element.id === payload.id);
  
  if (categoryIndex !== -1) {
    // Option 1: Replace the entire element (simple, works for reactivity)
    state.categories.splice(categoryIndex, 1, payload.updatedCategory);
    
    // Option 2: Merge new data into the existing object (preserves reactivity for nested properties)
    // Object.assign(state.categories[categoryIndex], payload.updatedCategory);
  }
}

2. Fix the Dispatch Call in Your Component

Update the updateCategory method to send a payload object instead of separate arguments:

updateCategory() {
  this.$store.dispatch('updateCategory', {
    id: this.$route.params.id,
    category: this.category
  });
}

3. (Optional) Ensure Reactivity for the category Object

If your API returns a category with properties that aren't initially present in the empty category object in data(), you might need to reassign it to ensure reactivity (though your current v-model setup should handle this fine). If you run into issues later, you could use:

// In getCategoryById's then() block
this.category = {...response.data}; // Spread to create a new reactive object

Verification

After making these changes, clicking the Update button will:

  1. Send the correct id and category data to your Vuex action
  2. Pass the updated category from the API to the mutation via a payload
  3. Correctly locate and update the category in the categories array
  4. Trigger Vue's reactivity system to update any components using this state

内容的提问来源于stack exchange,提问作者Thuan Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:41:38