首页 > 解决方案 > Vue.js 3 - 如何在 Vue 组件之间传递数据并让两个视图也更新?

问题描述

我尝试了以下。请注意 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')

父.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>

孩子.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>

标签: vue.jsvuexvuejs3vuex4

解决方案


你对与 Vue/Vuex 无关的 JavaScript 有一个误解。这不符合您的期望:

state = newState;

解决方案 (TL;DR)

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

不要设置state变量,而是合并新属性。

解释

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

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

但是,当您将整个变量(不仅仅是一个属性)更改为其他内容时,它不会改变原始引用的对象(即 Vuex 的状态)。它只是破坏了引用链接并为对象创建了一个新链接newState。所以 Vuex 状态根本不会改变。这是一个更简单的演示

观点

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


推荐阅读