【问题标题】:Updating an item in an array updates them all更新数组中的项目会全部更新
【发布时间】:2017-12-05 02:25:13
【问题描述】:

我正在开发一个使用 vuejs 和 vuex 的应用程序,它使用项目,每个项目都有一个或多个工作。

我可以添加、删除和更新作业。添加和删​​除工作完美,但更新不是。

vuex 开发工具中的状态:

我的 HTML:

<div class="job-compact row" v-for="(job, index) in project.jobs">
        <div class="col-md-6">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.function')}">
                <input type="text" name="jobs[function][]" class="form-control" v-model="job.function" @change="updateJobValue(index, 'function', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-4">
            <div class="form-group" :class="{'has-error' : errors.has('jobs.' + index + '.profiles')}">
                <input type="number" name="jobs[profiles][]" class="form-control" v-model="job.profiles" @change="updateJobValue(index, 'profiles', $event.target.value)"/>
            </div>
        </div>
        <div class="col-md-2">
            <button v-if="index == 0" class="btn btn-success btn-sm" @click="addJob"><i class="fa fa-plus"></i></button>
            <button v-if="index > 0" class="btn btn-danger btn-sm" @click="deleteJob(index);"><i class="fa fa-minus"></i></button>
        </div>
    </div>

如您所见,我有一个v-for,它显示了我所有的工作。在我的工作中编辑一个值时,我使用@change 事件来更新我的值。而且,在底部,我有两个按钮可以添加和删除作业行。

我的商店分为模块。主店长这样:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {};

const getters = {};

const mutations = {};

const actions = {};

//Separate Module States
import jobCreator from './modules/job-creator/store';

export default new Vuex.Store({
    modules: {
        jobCreator: jobCreator
    },
    state,
    actions,
    mutations,
    getters
});

针对这个特定问题的模块存储:

import store from './../../store'

const state = {
    project: {
        title: null,
        description: null,
        jobs: []
    },
    defaultJob: {
        function: '',
        title: '',
        description: '',
        profiles: 1,
        location_id: '',
        category_id: '',
        budget: '',
    },
};

const getters = {}

const mutations = {

    addJob(state, job) {
        state.project.jobs.push(job);
    },
    deleteJob(state, index) {
        state.project.jobs.splice(index, 1);
    },
    updateJobValue(state, params) {
        Object.assign(state.project.jobs[params.jobIndex], {
            [params.field]: params.value
        });
    }
};

const actions = {
    addJob: function (context) {
        context.commit('addJob', state.defaultJob);
    },
    deleteJob: function (context, index) {
        context.commit('deleteJob', index);
    },
    updateJobValue: function (context, params) {
        context.commit('updateJobValue', params);
    },
};

const module = {
    state,
    getters,
    mutations,
    actions
};

export default module;

项目状态映射到我的 vue 实例的计算属性:

computed: {
       ...mapState({
           project: state => state.jobCreator.project,
       }),
}

问题如下:在应用程序的图像中,您可以看到我在其中一个字段中输入了“vin”,但所有字段都在更新。

因此,所有工作的所有function 字段都已更新到我的最后一个条目,而不仅仅是我想要的。

我做错了什么?

PS:

我还在我的变异函数中尝试了以下内容:

updateJobValue(state, params) {
    var job = state.project.jobs[params.jobIndex];
    job[params.field] = params.value;

    Vue.set(state.project.jobs, params.jobIndex, job);
}

但它给了我同样的结果。

更新:根据要求,我创建了一个jsFiddle 来显示我的问题

【问题讨论】:

  • 你能把它变成一个 jsfiddle 吗?由于这是一个相当长的问题,因此人们会更容易帮助您。
  • 我添加了一个 jsfiddle 来解释我的问题

标签: javascript vue.js vuejs2 vuex


【解决方案1】:

问题在于您的addJob 操作:

addJob: function (context) {
    context.commit('addJob', state.defaultJob);
},

每次添加新作业时,您都在引用 state.defaultJob 对象。这意味着state.project.jobs 数组中的每个项目都引用同一个对象。

您应该在将对象传递给addJob 突变时创建对象的副本:

addJob: function (context) {
    context.commit('addJob', Object.assign({}, state.defaultJob));
},

或者,每次只传入一个具有默认属性的新对象:

addJob: function (context) {
    context.commit('addJob', {
        function: '',
        title: '',
        description: '',
        profiles: 1,
        location_id: '',
        category_id: '',
        budget: '',
    });
},

Here's a working fiddle.

这是一篇解释如何在 Javascript 中传递变量的帖子:Javascript by reference vs. by value

【讨论】:

    【解决方案2】:

    我会给出以下建议:

    使用v-bind:value="job.function 而不是v-model="job.function",因为您只需要单向绑定。这让您的代码更具可预测性。

    v-key="job" 添加到您的v-for="(job, index) in project.jobs" 元素中,以确保渲染正常工作。

    前两行应该够了,对象仍然是响应式的。

    var job = state.project.jobs[params.jobIndex];
    job[params.field] = params.value;
    
    
    Vue.set(state.project.jobs, params.jobIndex, job);
    

    PS:在我的小提琴中,@change 仅在我按 Enter 或离开输入时触发。

    【讨论】:

    • 我添加了一个 jsfiddle 来解释我的问题
    • 您的问题在于context.commit('addJob', state.defaultJob); 您一直在添加/引用同一个对象。只需将其更改为context.commit('addJob', Vue.extend({},state.defaultJob)),然后您将为每一行获得一个新对象。
    猜你喜欢
    • 2017-01-07
    • 2023-02-13
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    相关资源
    最近更新 更多