【问题标题】:Multiple Vue.js components with same Vuex store具有相同 Vuex 存储的多个 Vue.js 组件
【发布时间】:2020-02-06 03:08:39
【问题描述】:

在组件 1 中,有一些数据使用异步方法加载并存储在 Vuex 存储中。其他组件 2 正在使用相同的存储,当用户从组件 1 导航到组件 2 时,必须清除数据。

以下是正常工作的正常工作流程。

  1. 组件 1 - 加载数据已完成(异步、等待)
  2. 用户导航到组件 2
  3. 组件 1 数据在停用事件中被清除
  4. 组件 2 显示正常

现在,当用户打开组件 1 并快速导航到组件 2 时。

  1. 组件 1 - 数据请求已启动,但数据尚未加载
  2. 用户导航到组件 2
  3. 组件 1 数据在停用事件中被清除
  4. 组件 1 异步操作已完成,数据已加载到状态中
  5. 组件 2 将显示用于组件 1 的数据

【问题讨论】:

  • 为什么要将本地状态存储在全局 vuex 存储中?对我来说,这听起来像是你在滥用商店做一些不该做的事情。
  • 您可以添加一个状态来检查用户当前的导航页面,并在存储突变中设置一个标志来更新状态,只有用户在正确的组件中,否则忽略
  • @Sumurai8 还有一些常用的组件,比如组件1中的导航树,组件2是一样的,只是数据不同。
  • @chans,谢谢,这是一个很好的解决方案
  • @Sunny 支持以下解决方案,提前致谢

标签: vue.js vuex


【解决方案1】:

我仍然认为您应该重组您的组件,以便将数据加载到视图组件中而不是存储中。存储用于在不同视图之间共享的数据,或者至少与应用程序的更广泛部分相关,而您的数据似乎只特定于一个视图。只需通过 props 传递数据即可。

Views
- View A
- View B
Components
  Common
    - Sidebar (the common sidebar that is loaded in both View A and View B)
  - Some other components specific to view a and b

如果您打算继续使用商店存储本地数据,我认为您有多种选择:

  • 您可以使用 url 或视图名称来键入加载程序。在您的状态下,您通常只会拥有数据,现在您拥有一个将路线或视图名称映射到某些数据的对象。然后,您可以使用自动为您获取正确数据的 getter。这样做的额外好处是,您可以根据需要保留数据,这会在您返回该视图时加快加载速度(您不再需要进行 api 调用)。
  • 您将一些令牌提交到存储区,并且仅当令牌与检索令牌匹配时才覆盖存储状态中的数据。 (例如 dispatch('get/my/data', { token: 'asdf' }) 而之前在做 commit('switch/to/view', 'asdf')。如果视图与我们当前所在的视图不匹配,我们只需丢弃数据。

在这两种情况下,您都可以使用 dispatch('get/my/data', { view: this.$options.name })(或:this.$route.paththis.$route.name)之类的方式发送加载操作

如果您选择使用组件名称的方式,您将必须按照上面的说明进行提交。否则,您可以简单地使用 import router from '../router' 或类似名称导入您的路由器。

对于第一个选项,您会得到如下内容:

从'../router'导入路由器; 从'vue'导入Vue;

{
  state: {
    data: {},
  },
  getters: {
    getData (state) {
      return state.data[router.currentRoute.path];
    }
  },
  mutations: {
    setData (state, { view, data }) {
      Vue.$set(state.data, view, data);
    }
  },
  actions: {
    async fetchData ({ commit }, { view }) {
      const data = await myApiPromise;

      commit('setData', { view, data });
    }
  }
}

现在getData 如果您已加载该视图的数据,则返回数据,如果您尚未加载,则返回undefined。切换只会抓取之前存储的数据,这些数据可能对您有用,也可能对您有用。

第二个选项类似,但您需要担心一个额外的突变。在每个视图中从created 调用该突变。销毁组件时不必担心自己进行清理,而是在进行提取之前进行清理。

{
  state: {
    data: null,
    view: '',
  },
  getters: {
    getData (state) {
      return state.data[router.currentRoute.path];
    }
  },
  mutations: {
    clearData (state) {
      Vue.$set(state, 'data', null);
    },
    setData (state, { view, data }) {
      if (state.view !== view) {
        // Do not update
        return;
      }

      Vue.$set(state, 'data', data);
    },

    setView (state, { view }) {
      Vue.$set(state, 'view', view);
    }
  },
  actions: {
    async fetchData ({ commit }, { view }) {
      commit('clearData');
      const data = await myApiPromise;

      commit('setData', { view, data });
    }
  }
}

【讨论】:

    【解决方案2】:

    当用户从组件 1 导航到组件 2 时,在 Vue 生命周期中使用销毁的回调来清除存储

    来源:https://vuejs.org/v2/api/#destroyed

    您仍然可以添加一个状态来检查用户当前的导航页面,并在存储突变中设置一个标志来更新状态,只有用户在预期的组件中,否则忽略

    【讨论】:

    • 这是 OP 已经在做的事情,但是并发的美妙之处在于你的 promise(可能是一个 api 调用)可以在组件被销毁后完成,导致它加载错误的数据。跨度>
    猜你喜欢
    • 2017-07-25
    • 2018-11-23
    • 1970-01-01
    • 2014-08-18
    • 2017-12-19
    • 2018-12-14
    • 2021-08-14
    • 2022-01-22
    • 2019-05-30
    相关资源
    最近更新 更多