Vue.js 3 - 如何在 Vue 组件之间传递数据并同时更新两个视图?

Vue.js 3 - How can I pass data between Vue components and let both views also update?

我尝试了以下方法。 请注意 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,
          valueText: "",
          valueNumber: 0,
        },
        {
          id: 3,
          valueText: "",
          valueNumber: 0,
        },
      ],
    };
  },
  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",
  store,
  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>

您对 JavaScript 的误解与 Vue/Vuex 无关。这不符合您的预期:

state = newState;

解决方案 (TL;DR)

setState(state, newState) {
  Object.assign(state, newState);
}

不是设置 state 变量,而是将新属性合并到

说明

  • JavaScript中的对象变量是引用。这就是为什么如果您有多个变量引用同一个对象,并且您更改其中一个的 属性,它们都会发生变化。它们都只是引用内存中的同一个对象,它们不是克隆。

上面的 state 变量作为对 Vuex 状态对象的 引用 开始,你知道的。因此,当你改变它的属性时,你也会改变 Vuex 的状态属性。这样就好了。

但是当你将整个变量——不仅仅是一个属性——更改为其他东西时,它不会改变原始引用的对象(即Vuex的状态).它只是破坏了引用 link 并为 newState 对象创建了一个新的引用。所以 Vuex 状态根本不会改变。这是一个更简单的 demo.

意见

避免这种模式,而是在 state 上创建一个对象 属性。然后你可以做 state.obj = newState.

您应该使用传播运算符 ... 来改变您的状态,如下所示:

 state = { ...state, ...newState };

LIVE EXAMPLE

但我建议让您的商店以语义方式更有条理,您所在州的每个 属性 都应该有自己的 setteraction,吸气剂相当于计算选项中的属性 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,但如果您正在使用composition api 你可以使用 useStore 如下:

import {useStore} from 'vuex'
setup(){
    const store=useStore()// store instead of `$store`
}