在 Vuex 模块中添加一个内部管理其状态的复杂对象

Add in a Vuex modules a complex object which manages its status internally

我正在使用 Vuex,作为状态处理程序和工具在我的组件之间共享数据,这些组件不一定 "father-son"。

我想使用 Vuex 共享从外部库获取的复杂对象。 此对象具有更改其属性的方法。

对于这个对象,我不关心集中它的状态,但想要一种在组件之间共享它的方法。

我想到(并放弃)了不同的解决方案: - 禁用严格模式。但我想把它用于所有其他情况,非常有用! - 不要使用 Vuex。但它非常方便,而且它与调试工具集成得很好(例如chrome插件) - 用更简单的商店替换 Vuex:https://austincooper.dev/2019/08/09/vue-observable-state-store。和以前一样的问题

那么,从其他图书馆共享复杂数据的最佳方式是什么? 我想使用 vuex,但我找不到最干净的解决方案!

我的问题的一个例子: (按获取更多项目,将出现控制台错误) https://codepen.io/ale-grosselle/pen/dyyxyMr

class Item{
    id;
    constructor(i){
        this.id = Math.round(i * 100);
    }
}
//Share collection between the different components
class Collection {
    items;
    constructor(){
        this.items = [new Item(Math.random())];
    }   
    getMore(){
        const randomVal = (Math.random());
        this.items.push(new Item(randomVal));
    }
}
const store = new Vuex.Store({
    strict: true,
    state: {
        collection: new Collection()
    },
    mutations: {},
    getters: {
        collection(state) {
            return state.collection
        }
    },     
    modules: {}
})

new Vue({
    el: '#app',
    store,
    computed: {
        collection() {
            return this.$store.getters.collection;
        }
    },
    methods: {
        addNew() {
            this.collection.getMore();
        }
    }
})

尽管我理解您使用 Vuex 尝试通过您的应用程序共享对象的原因,但我认为这并不是目的,因为 objective 是共享单一数据源通过你的应用程序,你确切地说你不想要(确切地)那个。

如果需要,您可以共享集合 class 的单例实例,由模块导出,并使用 Provide/Inject API.

通过您的应用程序访问它

你会遇到的其他问题(因为我已经尝试在一个项目中做几乎相同的事情)是商店的状态必须是可序列化的,如果你不做任何特殊处理,当您使用 Chrome DevTools 中的 "time travel" 时,您的集合的方法将会丢失(因为状态是使用 JSON.stringify/JSON.parse 序列化和反序列化的)。

我知道这不是您想要的,但 Vuex 似乎不是您希望在您的情况下使用的东西。

编辑:我已经使用上面给出的想法更新了您的示例,并使用 Vue.observable 使对象对 Vue 具有反应性,您可以检查它 here:

class Item {
    id;
    constructor(i){
        this.id = Math.round(i * 100);
    }
}

//Share collection between the different components
class Collection {
    items;
    constructor(){
        this.items = [new Item(Math.random())];
    }   
    getMore(){
        const randomVal = (Math.random());
        this.items.push(new Item(randomVal));
    }
}

// Make it observable
const collection = Vue.observable(new Collection());

// Export like a singleton from some module
// export default collection

// provide anywhere on top, for example, in the app itself.
new Vue({
    el: '#app',
    provide: {
        'collection': collection
    },
})

// inject anywhere "below" and use it
const ChildComponent = Vue.component('child-component', {
    template: `
        <button @click='addNew'>Get more items</button>
    `,
    inject: ['collection'],
    methods: {
        addNew() {
            this.collection.getMore();
        }
    }
});

// template
<div id='app'>
    <pre>{{ collection }}</pre>
    <div v-for='item in collection.items'>
        {{ item.id }}
    </div>
    <child-component />
</div>