Vuex getter JSON.stringify 不是反应式的

Posted

技术标签:

【中文标题】Vuex getter JSON.stringify 不是反应式的【英文标题】:Vuex getter JSON.stringify is not reactive 【发布时间】:2020-05-26 09:21:51 【问题描述】:

我在这里有以下 Vuex 商店:

const store = new Vuex.Store(
    state: 
        renderedBlocks: []
    ,
    getters: 
        asString: (state) => () => 
            return JSON.stringify(state.renderedBlocks);
        ,
        block: (state) => (k) => 
            return state.renderedBlocks[k];
        
    ,
    mutations: 
        updateBlock(state, data) 
            if (!state.renderedBlocks[data.id])  return; 
            state.renderedBlocks[data.id].params = data.params;
            state.renderedBlocks[data.id].content = data.content;
        ,
        updateBlockIndex(state, data) 
            var s = state.renderedBlocks[data.id];
            s.content[data.index] = data.value;
            state.renderedBlocks[data.id] = s;
        
    
);

此状态跟踪 Wisiwyg 编辑器中的所有“块”(例如标题、图像、段落等)。

为了在提交表单时发送所有这些,我需要将此数据传递给 json 并将其分配给隐藏的文本字段。根据 Vue devtools,商店更新正确,但“asString”getter 没有更新 JSON。

这是所有已注册块的所有组件(即编辑器中可见的组件)的渲染位置:

<template>
    <div class="zg-content">
        <component v-for="(block, c) in $store.state.renderedBlocks" :is="block.component" :key="c"></component>
    </div>
</template>

这是输出发生的地方:

<template>
    <input type="hidden" :name="name" :value="asString">
</template>

<script>
export default 
    computed: 
        asString() 
            return this.$store.getters.asString();
        
    
;
</script>

这就是一个块的更新可能发生的地方:

<template>
    <ul ref="input">
        <li :key="key" v-on:keydown.enter="addElement(key, $event)" v-for="(point, key) in innerContent" contenteditable="true" v-html="point.content" @blur="updateContent(key, $event)"></li>
    </ul>
</template>

<script>
export default 

    props: ,

    computed: 
        params: 
            set(v) ,
            get()  return this.$store.getters.block(this.$vnode.key).params; 
        ,
        innerContent: 
            set(v) ,
            get()  return this.$store.getters.block(this.$vnode.key).content; 
        
    ,

    methods: 
        addElement(index, event) 
            var self = this;
            event.preventDefault();

            this.innerContent.splice(index+1, 0, content: '');

            this.$store.commit('updateBlock', 
                id: this.$vnode.key,
                params: this.params,
                content: this.innerContent
            );
        ,
        updateContent(key, event) 
            this.$store.commit('updateBlockIndex', 
                id: this.$vnode.key,
                index: key,
                value: 'content': event.target.innerHTML 
            );
        
    
;
</script>

因此,当我添加新元素或修改现有元素时,会触发“li”的模糊事件。我的状态已正确更新 - 这意味着元素在商店中通过 'content': 'NewContent' 可见。但是隐藏输入中的JSON还是旧的。

我发现,当我在列表组件中创建所有列表元素的“私有”版本时,它按预期工作。但这并不是真正的“Vuex 方式”,在严格模式下我也会遇到很多错误。

【问题讨论】:

只有当我按下回车(意味着 updateBlock 突变被执行)时,JSON 才会更新 - 但不会使用 updateBlockIndex。似乎将新元素添加到列表中会被跟踪,而修改旧元素则不会。 【参考方案1】:

来自docs:

由于 javascript 的限制,Vue 无法检测到数组的以下更改: 当您直接使用索引设置项目时,例如vm.items[indexOfItem] = newValue

您可以使用spliceVue.set 来克服这个问题,因为它们都是可检测的。例如,在updateBlockIndex 中,将最后一行替换为:

state.renderedBlocks.splice(data.id, 1, s);

Vue.set(state.renderedBlocks, data.id, s);

如果您使用Vue.set,您还需要:

import Vue from 'vue'

您应该在updateBlock 中同样执行此操作。我猜它现在“起作用”的原因是因为spliceinnerContent

【讨论】:

谢谢 - 这行得通。从现在开始,用户界面将遵守该规则;)

以上是关于Vuex getter JSON.stringify 不是反应式的的主要内容,如果未能解决你的问题,请参考以下文章

Vuex - 何时使用 getter 以及何时使用状态

Vuex - Getter

如何从另一个 vuex 模块访问 getter?

Vuex:从动作中调用 getter

Vuex 从 getter 访问 this.$store

单元测试依赖于其他 getter 的 Vuex getter