Vuex 不会对复杂对象做出反应
Vuex doesn't react with complex object
我已经开始使用 Vuex 来替换 EventBus,因为我的应用程序中的数据开始变得有点复杂。
在我的上下文中,我有一个问题实体,有多个答案,当用户插入另一个答案时,我想显示最后一个; (这里我使用了两个不同的组件:一个用于显示答案,另一个用于回答问题)但是当服务器响应新答案 OK 并且突变更改 state.answers 时,计算出的 属性 不会'反应不显示新答案:
这是我的数据结构:
"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 以及如何 "it not work well" 处理复杂数据的文章,所以我对数据进行了规范化。但它是一样的......我也尝试过使用vuex-orm,但是我在一对多关系方面有很多问题,我无法做到这一点。
编辑:解决方案
我根据答案中的想法做了一个小测试,它有效
setAnswer(state, answer) {
let newAnswers = state.answers;
state.answers = {};
newAnswers[answer.id] = answer;
state.answers = newAnswers;
}
您正在对象中存储答案列表。这没什么错,因为你知道如何处理。事实证明 Vue.js observers
不跟踪新的对象属性 (这正是你在那里所做的,创建新属性,而不是修改 list/array) .
我的第一个建议是将此对象更改为数组。但是如果你不能,由于你的ORM或者你的项目标准的其他原因,你应该看看Reactivity
of 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
当你使用对象时,你必须这样做
setAnswer(state, answer) {
Vue.set(state.answers, answer.id, answer);
},
文档中明确提到了这一点。
When adding new properties to an Object, you should either:
- Use Vue.set(obj, 'newProp', 123), or
-
Replace that Object with a fresh one. For example, using the object spread syntax we can write it like this:
state.obj = { ...state.obj, newProp: 123 }
我已经开始使用 Vuex 来替换 EventBus,因为我的应用程序中的数据开始变得有点复杂。
在我的上下文中,我有一个问题实体,有多个答案,当用户插入另一个答案时,我想显示最后一个; (这里我使用了两个不同的组件:一个用于显示答案,另一个用于回答问题)但是当服务器响应新答案 OK 并且突变更改 state.answers 时,计算出的 属性 不会'反应不显示新答案:
这是我的数据结构:
"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 以及如何 "it not work well" 处理复杂数据的文章,所以我对数据进行了规范化。但它是一样的......我也尝试过使用vuex-orm,但是我在一对多关系方面有很多问题,我无法做到这一点。
编辑:解决方案
我根据答案中的想法做了一个小测试,它有效
setAnswer(state, answer) {
let newAnswers = state.answers;
state.answers = {};
newAnswers[answer.id] = answer;
state.answers = newAnswers;
}
您正在对象中存储答案列表。这没什么错,因为你知道如何处理。事实证明 Vue.js observers
不跟踪新的对象属性 (这正是你在那里所做的,创建新属性,而不是修改 list/array) .
我的第一个建议是将此对象更改为数组。但是如果你不能,由于你的ORM或者你的项目标准的其他原因,你应该看看Reactivity
of 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
当你使用对象时,你必须这样做
setAnswer(state, answer) {
Vue.set(state.answers, answer.id, answer);
},
文档中明确提到了这一点。
When adding new properties to an Object, you should either:
- Use Vue.set(obj, 'newProp', 123), or
- Replace that Object with a fresh one. For example, using the object spread syntax we can write it like this:
state.obj = { ...state.obj, newProp: 123 }