【问题标题】:Vuex mutate object best practicesVuex 变异对象最佳实践
【发布时间】:2021-07-31 20:55:06
【问题描述】:

我正在开发一个模块,使用户能够在对象上添加注释。我使用 Vuex 商店和一个组件来可视化备注。我已经粘贴了下面的代码。

问题是我将显示备注正文的文本区域绑定到作为备注对象的属性正文的 v-model。由于我使用 getremarks getter 从商店返回备注数组,因此对备注对象属性的任何更改也会在商店中直接更改,因为它是被传递的同一个对象。因此,我有效地绕过了 Vuex 希望我实现的整个动作/突变模式。

我总是可以将变异的评论传递给商店中的动作和变异,但这意味着我正在变异一个已经变异的对象。我想知道周围是否有任何最佳做法?

商店

import Vue from 'vue'

const model = {
    state: {
        remarks: [],
    },

    mutations: {
        SET_REMARKS(state, remarks) {
            state.remarks = remarks;
        }
    },

    getters: {
        getRemarks(state) {
            return state.remarks;
        },
        getRemarkById: (state) => (id) => {
            return state.remarks.find(remark => remark.model_remark_id === id);
        }
    },

    actions: {
        
    }
}

export default model;

组件

<template>
    <v-list two-line expand>
        <v-list-group v-for="remark in remarks" :key="remark.model_remark_id">
            <template v-slot:activator>
                <v-list-item-icon>
                    <v-icon v-text="icon" :color="remark.priority === 1 ? 'red' : remark.priority === 2 ? 'orange' : '#1478c7'" />
                </v-list-item-icon>
                <v-list-item-content>
                    <v-list-item-title><b>{{ remark.created_by_user.name  }}</b></v-list-item-title>
                    <v-list-item-subtitle>Created at {{ moment(remark.created_at).format('DD-MM-YYYY HH:ss:mm')  }}</v-list-item-subtitle>
                </v-list-item-content>
            </template>

            <v-list-item>
                <v-list-item-icon>
                    &nbsp;
                </v-list-item-icon>
                <v-list-item-content>
                    <v-row>
                        <v-col>
                            <v-textarea
                                class="mx-2"
                                v-model="remark.body"
                                auto-grow
                            />
                        </v-col>
                    </v-row>
                    <v-row>
                        <v-col align="right">
                            <v-btn
                            color="primary"
                            elevation="2"
                            @click="remarkDone(remark)"
                            >Done</v-btn>
                            &nbsp;
                            <v-btn
                            color="primary"
                            elevation="2"
                            @click="remarkUpdate(remark)"
                            >Update</v-btn>
                        </v-col>
                    </v-row>
                </v-list-item-content>
            </v-list-item>
        </v-list-group>
    </v-list>
</template>

<script>
import { mapGetters, mapActions } from "vuex";

export default {
    data: () => ({
        icon: "mdi-comment"
    }),
    computed: {
        remarks: function () {
            return this.getRemarks();
        },
    },
    methods: {
        ...mapGetters([
            "getRemarks",
            "getRemarkById"
        ]),

        remarkUpdate(remark) {
            console.log(remark);

            const x = this.getRemarkById()(remark.model_remark_id);

            console.log(x);
        }
    },
};
</script>

【问题讨论】:

  • 您可以先克隆对象,然后再在组件中使用它们。

标签: vue.js vuex


【解决方案1】:

我认为这里要记住的关键原则是关注点分离。让 Vuex 处理所有的状态变化,让你的 Vue 组件简单地从状态中获取备注。状态是响应式的,因此如果您从组件调用突变来更改您的备注,您希望组件简单地响应该更改并呈现更新的标记。

此外,您应该使用mapGetters 将您的getter 映射到computed 属性,而不是方法。我也不确定您是否需要 updateRemark() 中的 getRemarkById getter,因为您已经将备注作为参数。

export default {
  computed: {
    ...mapGetters({ remarks: 'getRemarks' })
  },
  methods: {
    updateRemark(remark) {
      // here you should commit a mutation to update your remark
      this.$store.commit('updateRemark', remark)
    }
  }
}

【讨论】:

  • 谢谢,但它确实感觉像是为已经更改的对象调用突变的冗余逻辑。我可以看到反应性的论点。感谢您提供有关计算属性中的 mapgetter 的提示!
  • 我看不到您正在更改组件内的对象。用户单击按钮来更新备注,然后调用 updateRemark 方法。此时您的备注对象尚未被触及。所以只要你让 Vuex 处理任何突变,你就应该很好。
  • 我的错,剥离了一些代码,但 remarkDone 方法触及了对象,remarkUpdate 仅仅是记录信息/保存更新。我理解让 Vuex 进行实际变异的重要性,这让我回到了最初的问题,在 Vuex 商店中变异复杂对象的好方法是什么。我可以看到几个选项,按照上面 IVO GELOV 的建议进行克隆,触摸对象并按照您的代码示例所暗示的那样在突变中再次执行它,因为它传递给已经接触过的对象到突变。两者都意味着我实现了不需要恕我直言的逻辑?
  • 你是对的,你不应该在你的组件和突变中实现相同的逻辑。这是重复的,而不是理想的模式。在 remarkDone 中,不是触摸对象,而是调用一个突变来代替它。突变后,更新的状态将提供给您的组件。例如,remarkDone(remark) { this.$store.commit('remarkDone', remark) }
  • 好吧,看来我得稍微解决一下 Vuex 了。感谢您的输入
猜你喜欢
  • 2017-09-21
  • 1970-01-01
  • 2018-10-03
  • 2012-07-31
  • 2018-02-14
  • 2021-06-05
  • 1970-01-01
  • 2011-07-12
  • 2011-12-27
相关资源
最近更新 更多