【问题标题】:Vuex state updates break v-for reactivityVuex 状态更新中断 v-for 反应性
【发布时间】:2021-10-13 22:52:14
【问题描述】:

我正在尝试使用内置的 Vuex 商店在 Nuxt 中制作一个通知组件。我有两个组件,Notifications.vueNotification.vue 来显示通知。我的商店有两个突变,一个用于添加通知,另一个用于删除一个。

以下是我项目中的相关文件:

store/notifications.js

export const state = () => ({
    notifications: []
});

export const getters = {
    allNotifications: state => state.notifications
};

export const mutations = {
    PUSH_NOTIFICATION(state, notification) {
        state.notifications.push(notification);
    },
    REMOVE_NOTIFICATION(state, notificationToRemove) {
    // PROBLEM ---> Updates state but breaks reactivity
        state.notifications = [
            ...state.notifications.filter(notification => notification.id != notificationToRemove)
        ];
};

export const actions = {
    async pushNotification({ commit }, notification) {
        return new Promise((resolve, reject) => {
            notification = {
                ...notification,
                id: (Math.random().toString(36) + Date.now().toString(36)).substr(2)
            };
            commit('PUSH_NOTIFICATION', notification);
            resolve(notification.id);
        });
    },
    async removeNotification({ commit }, id) {
        return new Promise((resolve, reject) => {
            commit('REMOVE_NOTIFICATION', id);
            resolve();
        });
    }
};

plugins/notifications.js

export default ({ store }, inject) => {
    let notifications = {
        async notify(notification) {
            return await store.dispatch('notifications/pushNotification', notification);
        },
        async removeNotification(id) {
            console.log(`The notification with the id ${id} will be removed!`);
            await store.dispatch('notifications/removeNotification', id);
            return true;
        }
    };
    // This allows me to access the methods above from any component like `this.$notifications`
    inject('notifications', notifications);

};

components/Notifications.vue

<template>
    <div class="notifications">
        <button @click="test()">Notify</button><!-- This is to test adding new notifications -->
        <div class="notification-bounds">
            <Notification v-for="notification in notifications" :key="notification.id" :id="notification.id">{{ notification.content }}</Notification>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                notifications: this.$store.getters['notifications/allNotifications']
            };
        },
        methods: {
            test() {
                // This works therefore `PUSH_NOTIFICATION` does not break reactivity
                this.$notifications.notify({ content: 'Test' }); 
            }
        }
    };
</script>

components/Notification.vue

<template>
    <div class="notification">
        <slot></slot>
        <button @click="close()">Close</button>
    </div>
</template>

<script>
    export default {
        props: [
            'id'
        ],
        methods: {
            close(){
    // PROBLEM ---> This updates the state internally but it breaks reactivity so 
    // there is something wrong with the `REMOVE_NOTIFICATION` mutation.
                this.$notifications.removeNotification(this.id) 

            }
        }
    };
</script>

问题在于REMOVE_NOTIFICATION 突变破坏了Notifications.vuev-for 的反应性。我该如何解决这个问题?

【问题讨论】:

  • 弄清楚所有这些逻辑的问题是什么而不是“破坏反应性”的视觉指示有点复杂。同时,由于您在 Nuxt 后面使用 Vue2,您可能在数组警告中? vuejs.org/v2/guide/reactivity.html#For-Arrays
  • @kissu 我不认为我在数组警告范围内,因为我没有设置notifications 数组的特定属性,也没有像state.notifications.length = newLength 那样更改它的长度。我只是将notifications 数组设置为filter 方法返回的新数组。我觉得就好像我在 REMOVE_NOTIFICATION: state.notifications = newNotificationsArray 做这个。
  • @kissu 顺便说一句,当我说“破坏反应性”时,我的意思是REMOVE_NOTIFICATION 正确地改变了状态(我可以通过在返回的浏览器控制台中调用window.$nuxt.$store.getters['notifications/allNotifications']; 来验证这一点更新状态正确。)但更改未反映在浏览器页面中,因此当我删除通知时,浏览器不会从页面中删除相应的 Notification 组件。

标签: vue.js nuxt.js state vuex store


【解决方案1】:

好吧,缺少 reactivity 是因为您确实在 data 中获取通知。
data 的目标是静态的,实际上不会重新计算任何更改。

在你的 Notifications.vue 文件中试试这个

<script>
export default {
  computed: {
    notifications() {
      return this.$store.getters['notifications/allNotifications']
    },
  },
}
</script>

【讨论】:

    猜你喜欢
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2021-06-19
    • 2018-10-02
    • 1970-01-01
    • 2017-05-20
    • 1970-01-01
    相关资源
    最近更新 更多