Vuex不会对复杂对象做出反应

时间:2019-11-25 19:42:52

标签: javascript vue.js vuex mutation

我已经开始使用Vuex来替换EventBus,因为我的应用程序中的数据开始变得有点复杂了。

在我的上下文中,我有一个带有多个答案的问题实体,当用户插入另一个答案时,我想显示最后一个答案; (在这里,我使用了两个不同的组件:一个用于显示答案,另一个用于回答问题),但是当服务器对新答案的响应为OK,并且突变更改了state.answers时,计算出的属性不会做出反应,并且不会t显示新答案:

这是我的数据结构:

"answers": {
  "118": {
    "id": 118,
    "description": "objective",
    "created_at": "2019-11-12T19:12:36.015Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  }
  "127": {
    "id": 127,
    "description": "asdddd",
    "created_at": "2019-11-12T19:38:19.233Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  },
  "128": {
    "id": 128,
    "description": "asddddasddd",
    "created_at": "2019-11-12T20:00:17.572Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  }
},

这是我商店的代码:

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

Vue.use(Vuex);     

export const store = new Vuex.Store({
  state: {
    ...
    answers: {},
    ...
  },

  getters: {

    findBy: state=> filter => {
      let result= Object.values(state[filter.model]).
      filter(data => data[filter.field] === filter.criteria);
      return result;
    }
  },
  mutations: {

    setAnswers(state, answers) {
      state.answers = answers;
    },
    setAnswer(state, answer) {
      state.answers[answer.id] = answer;
    },

  },
  actions: {
    replaceCompleteProcess(context, data) {
      ...
      context.commit('setAnswers',data.answers);
      ...

    },
    cleanCompleteProcess(context) {
      ...
      context.commit('setAnswers',{});      
      ...
    },
    saveAnswer(context, answer) {
      context.commit('setAnswer', answer);
    }
  }
});

这是我组件脚本的结构:

export default {
name: "show-question",
computed: {
  question: function () {
    return this.$store.getters.question(this.questionId)
  },
  answers: function () {
    return this.$store.getters.findBy({
      model: 'answers',
      field: 'question_id',
      criteria: this.questionId,
      sort: true
    });
  },
  answer: function () {
    if (this.answers && this.answers.length > 0) {
      return this.answers[0].description;
    } else {
      return '';
    }
  }
},
props: {
  questionId: {
    type: [Number],
    default: 0
  }
},
data() {
  return {
    sending: false,
    answerData: this.answer
  }
},
methods: {
  sendAnswer () {
    this.sending = true;
    questionConnector.answerQuestion(this,this.question.id,this.dojoProcessId, this.answerData)
  },

 // this one is called from AXIOS
  answerWasOK(answer) {
    this.sending = false;
    this.$store.dispatch('saveAnswer', answer);
    this.answerData = '';
  }
}

}

因此,如果我了解如何使用Vuex,则在调用this。$ store.dispatch('saveAnswer',answer)时,状态将被更新,计算所得的属性答案将被更新,能够显示组件中的新更改,但是它不起作用。...计算出的属性只是没有反应。

我已经阅读了很多有关vuex的信息,以及有关复杂数据如何“不起作用”的知识,因此我将数据标准化了。但这是相同的...我也尝试使用vuex-orm,但是我与一对多关系存在很多问题,我无法做到这一点。

编辑:解决方案

我对答案中的想法进行了小测试,并且效果很好

setAnswer(state, answer) {
    let newAnswers = state.answers;
    state.answers = {};
    newAnswers[answer.id] = answer;
    state.answers = newAnswers;
}

2 个答案:

答案 0 :(得分:4)

使用对象时,必须像这样

setAnswer(state, answer) {
    Vue.set(state.answers, answer.id, answer);
},

文档中明确提到了这一点。

在向对象添加新属性时,您应该:
        
  • 使用Vue.set(obj,'newProp',123),或
  •     
  •         用一个新的对象替换该对象。例如,使用对象传播语法,我们可以这样编写:         
            state.obj = {... state.obj,newProp:123}     

答案 1 :(得分:1)

您正在将答案列表存储在对象内部。没问题,因为您知道如何处理。事实证明, Vue.js observers不会跟踪新的对象属性(这正是您在此处所做的,创建新属性,而不是修改列表/数组)。

我的第一个建议是将该对象更改为数组。但是,如果不能,由于您的ORM或项目标准的其他原因,您应该查看Reactivity中的Vue.js。我认为最快的解决方案是使用watcher

https://vuejs.org/v2/api/#watch


一些有助于理解Vue.js反应性的链接:

深度反应性

https://vuejs.org/v2/guide/reactivity.html

如何主动跟踪对象属性更改?

https://forum.vuejs.org/t/how-to-actively-track-an-object-property-change/34402/1