问题描述
我尝试了以下方法。 请注意parent.vue中的注释行,它甚至没有为我提交新状态。 但是,也许有人可以引导我找到由多个组件共享的全局状态的更好解决方案?
main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createStore } from 'vuex'
const app = createApp(App);
export const store = createStore({
state: {
textProp: 'test',count: 1
},mutations: {
setState(state,newState) {
console.log('setState');
state = newState;
}
},getters: {
getAll: (state) => () => {
return state;
}
}
});
app.use(store);
app.mount('#app')
parent.vue
<template>
<div class="parent">
<div class="seperator" v-bind:key="item" v-for="item in items">
<child></child>
</div>
<button @click="toonAlert()">{{ btnText }}</button>
<button @click="veranderChild()">Verander child</button>
</div>
</template>
<script>
import child from "./child.vue";
import {store} from '../main';
export default {
name: "parent",components: {
child,},store,data: function () {
return {
items: [
{
id: 1,valueText: "",valueNumber: 0,{
id: 2,{
id: 3,],};
},props: {
btnText: String,methods: {
toonAlert() {
alert(JSON.stringify(this.$store.getters.getAll()));
},veranderChild() {
console.log('child aan het veranderen (parentEvent)');
this.$store.commit('setState',{ // This is especially not working.
textProp: 'gezet via de parent',count: 99
})
this.$store.commit({type: 'setState'},{
'textProp': 'gezet via de parent','count': 99
});
},};
</script>
<style>
.seperator {
margin-bottom: 20px;
}
.parent {
/* background: lightblue; */
}
</style>
child.vue
<template>
<div class="child">
<div class="inputDiv">
text
<input @change="update" v-model="deText" type="text" name="deText" />
</div>
<div class="inputDiv">
nummer
<input v-model="hetNummer" type="number" name="hetNummer" />
</div>
<button @click="toonState">Toon huidige state</button>
</div>
</template>
<script>
import {store} from '../main';
export default {
name: "child",data: function() {
return {
'hetNummer': 0
}
},methods: {
update(e) {
let newState = this.$store.state;
newState.textProp = e.target.value;
// this.$store.commit('setState',newState);
},toonState()
{
console.log( this.$store.getters.getAll());
}
},computed: {
deText: function() {
return '';
// return this.$store.getters.getAll().textProp;
}
}
};
</script>
<style>
.inputDiv {
float: right;
margin-bottom: 10px;
}
.child {
max-width: 300px;
height: 30px;
margin-bottom: 20px;
/* background: yellow; */
margin: 10px;
}
</style>
解决方法
您对与Vue / Vuex无关的JavaScript有误解。这没有达到您的期望:
state = newState;
解决方案(TL; DR)
setState(state,newState) {
Object.assign(state,newState);
}
合并新属性而不是设置state
变量。
说明
-
JavaScript中的
- 对象变量是引用。这就是为什么如果您有多个变量引用同一个对象,而您更改了一个对象的属性,则它们都会发生变化。它们都只是引用内存中的同一对象,不是克隆对象。
上面的state
变量作为对Vuex状态对象的引用开始。因此,当您更改其属性时,也会同时更改Vuex的状态属性。很好。
但是,当您将整个变量(不仅仅是一个属性)更改为其他变量时,它不会不变异原始引用的对象(即Vuex的状态)。它只是断开引用链接,并为newState
对象创建一个新链接。因此,Vuex状态根本不会改变。这是一个更简单的demo。
意见
避免使用此模式,而是在state
上创建对象属性。然后,您可以执行state.obj = newState
。
您应该使用传播运算符...
来更改状态,如下所示:
state = { ...state,...newState };
但是我建议您以语义方式使您的商店更井井有条,您所在州的每个属性都应有自己的setter
和action
,getter等同于选项API中的计算属性,基于多个状态属性。
export const store = createStore({
state: {
count: 1
},mutations: {
SET_COUNT(state,_count) {
console.log("setState");
state.count=_count
},INC_COUNT(state) {
state.count++
}
},getters: {
doubleCount: (state) => () => {
return state.count*2;
}
}
});
**注意:**无需从每个孩子的main.js
导入商店,因为可以在选项api中使用this.$store
来使用商店,但是如果您使用的是api,则可以使用{ {1}}如下:
useStore