Vue/Vuex - 模块二依赖于模块一,模块一从服务器获取数据

Posted

技术标签:

【中文标题】Vue/Vuex - 模块二依赖于模块一,模块一从服务器获取数据【英文标题】:Vue/Vuex - Module two depends on module one, and module one gets data from server 【发布时间】:2019-09-29 07:07:30 【问题描述】:

看看这个:

import accountModule from '@/store/modules/account/account';
import otherModule from '@/store/modules/other/other';

export default new Vuex.Store(
  modules: 
    account: accountModule,
    other: otherModule,
  
);

other 中的数据初始化依赖于account 模块,因为account 模块具有用户特定的设置。假设other.state.list 依赖于account.state.settings.listOrder。但是,我希望account 模块的数据来自服务器。这是异步的。因此,当other 尝试设置时,它不能只尝试引用account.state.settings.listOrder,因为服务器的响应可能还没有回来。

我尝试在accountModule 中导出一个promise,它可以通过模块本身解决。但这种方法似乎行不通。

import accountModulePromise from '@/store/modules/account/account';

accountModulePromise.then(function (accountMoudle) 
  import otherModule from '@/store/modules/other/other';

  ...
);

这给了我一个错误,说 import 语句需要是***的。

以下也不起作用:

let accountModule = await import '@/store/modules/account/account';
import otherModule from '@/store/modules/other/other';
...

它给了我一个错误,说await 是一个保留字。不过我很困惑,因为https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Statements/import 说我应该能够做到。

【问题讨论】:

仍然,为什么要延迟 vuex 模块 的导入。或者你想在otherModuleaccountModule 上进行操作? @Frank 最后,我希望otherModule 中的数据设置等待accountModule。但为了做到这一点,我认为我需要延迟accountModule 的导入,因为我希望第二行代码仅在第一行完成从服务器获取其内容并进行设置时执行。 好像 other 依赖于 account,那么 otherModule 应该导入 accountModule。试图在商店里解决似乎是错误的。究竟是什么依赖? @eric99 在otheraccount 的子模块的意义上?如果是这样,那不是我想要的结构方式。如果没有,还有一个问题是我将 account 附加到我的 Vuex 商店的位置。如果我开始在多个地方导入它,它会因大量不必要的网络请求而减慢速度。在我的真实应用程序中还有一个更复杂的问题(我在这个问题中忽略了以保持简单),有许多模块依赖于account 如果你使用标准的 Vue CLI 设置,导入不是运行时指令——而是 webpack 使用然后捆绑代码。因此,await 不能与它一起使用,并且您不能分配它的结果(它不是函数调用),并且多个引用不会“减慢速度”。您应该将导入视为编译时声明而不是运行时指令。 【参考方案1】:

您的最后一个代码块不起作用,因为 await 必须在 async 函数内。

请记住,await 关键字仅在异步函数中有效。如果 你在异步函数体之外使用它,你会得到一个 语法错误。

来自MDN。

你可以使用Dynamic Module Registration:

accountModulePromise.then(async () => 
  let otherModule = await import('@/store/modules/other/other');
  store.registerModule('other', otherModule.default);
);

但是当您想要获取状态或调度操作时,您必须检查模块是否已注册,这很糟糕。

在我看来,如果您重新设计模块结构以相互解耦会更好。尝试将您的初始化代码移动到 main.jsApp.vue,然后调度操作以从中更新模块状态。


更新

从你上次的更新,另一个解耦你的商店的想法,我认为你应该存储你的 list 没有订单,只有在你使用时才对其进行排序。你可以这样做:

计算属性:

...
computed: 
  list () 
    let list = this.$store.state.other.list
    let order = this.$store.state.account.settings.listOrder
    if (!list || !order) return []
    return someSort(list, order)
  
,

beforeCreate () 
  this.$store.dispatch('other/fetchList')
  this.$store.dispatch('account/fetchListOrder')

...

或 Vuex 吸气剂:

...
getters: 
  list: (state) => (order) => 
    return someSort(state.list, order)
  

...
...
computed: 
  list () 
    let order = this.$store.state.account.settings.listOrder
    return this.$store.getters['others/list'](order)
  

...

【讨论】:

我很想在main.jsApp.vue 中初始化代码,但是我很难找到一个好的方法来做到这一点。在App.vue 中,计时已关闭,App.vue 在我的 Vuex 设置后运行。 main.js我不知道这会如何工作。我希望帐户资料在我的商店中。我曾想过将我的帐户内容附加到 window 并从需要它的商店引用它,但这很难看。 “但是当你想要获取状态或调度动作时,你必须检查模块是否已注册,这很糟糕。” 我的想法是隐藏所有内容,直到商店都已初始化。 IMO 还不错。 @AdamZerner 我根据您的上次更新更新我的答案。不确定您还有其他顾虑。 await import(...) 方法在某种意义上是有效的,但它会导致其他问题。在store/index.js 中,我想导出商店,但如果我在accountModulePromise 中注册模块,它会在设置之前找出其他东西试图使用商店的位置。我还尝试将所有内容都放在异步 IIFE 中,但也遇到了同样的问题。 至于将 store 解耦的想法,我很欣赏它,它可能是我现实世界用例的最佳方法,但我仍然对更一般的问题感兴趣。 【参考方案2】:

好的,所以你有两个模块。一个具有从服务器获取的状态,另一个具有依赖于第一个状态的状态,对吗?

我会建议以下方法:

首先将您的模块设置为空“状态”。然后在 accountModule 中创建一个动作来设置服务器的状态。在other 上使用getter 对列表进行排序。最后,在应用创建时分派您的操作。

const account = 
    namespaced: true,
    state: 
        listOrder: ''
    ,
    mutations: 
        setListOrder (state, newListOrder) 
            state.listOrder = newListOrder
        
    ,
    actions: 
        async fetchServerState (ctx) 
            let result = await fetch("/path/to/server")
            ctx.commit('setListOrder', result.listOrder) 
            // or whatever your response is, this is an example
        
    


const other = 
    namespaced: true,
    state: 
        unorderedList: []
    ,
    getters: 
        list (state, getters, rootState) 
            return someSort(state.unorderedList, rootState.account.listOrder);
        
    



在 App.vue 中(或任何地方)

created () 
    this.$store.dispatch('account/fetchServerState')

【讨论】:

出于几个原因,我更喜欢在存储模块文件中进行初始化,但你的方法还不错。

以上是关于Vue/Vuex - 模块二依赖于模块一,模块一从服务器获取数据的主要内容,如果未能解决你的问题,请参考以下文章

Vue2 Vuex在大型项目中的应用

javascript Vue Vuex打字稿模块操作导出

依赖倒置原则

你如何找出哪些 NPM 模块依赖于你的?

VUE - 未找到模块。无法导入组件

IOC