【问题标题】:How to re-use component that should use unique vuex store instance如何重用应该使用唯一 vuex 存储实例的组件
【发布时间】:2020-03-02 06:59:39
【问题描述】:

我试图找到一种将 vuex 与可重用组件一起使用的方法,该组件将数据存储在商店中。问题是,我需要商店对于每个组件实例都是唯一的。

我认为文档的可重用模块是关键,但最后似乎不是为了这个目的,或者我不明白如何使用它。

父组件: (prop “req-path” 用于传递不同的 URL 以使每个 FileExplorer 组件提交从 API 获取数据的操作,具有该 url 路径)

<template>
  <div class="container">
    <FileExplorer req-path="/folder/subfolder"></FileExplorer>
    <FileExplorer req-path="/anotherfolder"></FileExplorer>
  </div>
</template>

<script>
import { mapState, mapGetters } from "vuex";
import FileExplorer from "@/components/FileExplorer.vue";

export default {
  components: {
    FileExplorer
  }
};
</script>

可重用组件:

<template>
 <div class="container">
      <ul v-for="(item, index) in folderIndex" :key="index">
        <li>Results: {{ item.name }}</li>
      </ul>
    </div>
 </div>
</template>

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

export default {
  props: ["reqPath"],
  },
  computed: {
    ...mapState("fileExplorer", ["folderIndex"])
  },
  created() {
    // FETCH DATA FROM API
    this.$store
      .dispatch("fileExplorer/indexingData", {
        reqPath: this.reqPath
      })
      .catch(error => {
        console.log("An error occurred:", error);
        this.errors = error.response.data.data;
      });
  }
};
</script>

store.js 我在其中调用我在不同文件中分隔的商店模块,这里只有 fileExplorer 模块对我们感兴趣。 编辑:为了清楚起见,我简化了文件,但我还有一些其他状态和许多突变。

import Vue from 'vue'
import Vuex from 'vuex'

// Import modules
import { fileExplorer } from '@/store/modules/fileExplorer'

Vue.use(Vuex)

export default new Vuex.Store({
modules: {
    fileExplorer,
…
  }
})

@/store/modules/fileExplorer.js

import ApiService from "@/utils/ApiService"

export const fileExplorer = ({
namespaced: true,

  state: {
    folderIndex: {},
},

  mutations: {
    // Called from action (indexingData) to fetch folder/fil structure from API
    SET_FOLDERS_INDEX(state, data) {
      state.folderIndex = data.indexingData
},

actions: {
    // Fetch data from API using req-path as url 
    indexingData({
      commit
    }, reqPath) {
      return ApiService.indexingData(reqPath)
        .then((response) => {
          commit('SET_FOLDERS_INDEX', response.data);
        })
        .catch((error) => {
          console.log('There was an error:', error.response);
        });
    }
  }
});

我需要每个组件显示来自这 2 个不同 URL 的不同数据,而不是我在 2 个组件实例中获得相同的数据(不过这并不奇怪)。

非常感谢所有阅读所有内容的人!

【问题讨论】:

  • 类似folderIndex 的声音不应存储在全局状态中,而应存储在每个FileExplorer 组件的本地状态中。返回ApiService.indexingData(reqPath) 并在created 方法中处理响应,您可以将其添加到本地状态
  • 对不起,我忘了提到我简化了我的商店模块文件,但我还有一些其他的状态和许多突变。如果只是为了获取数据,我确实会使用您的解决方案。

标签: vue.js vuejs2 vue-component vuex vuex-modules


【解决方案1】:

模块重用是指您从同一个模块配置创建多个模块时。


首先,使用一个函数来声明模块状态,而不是一个普通的对象。

如果我们使用普通对象来声明模块的状态,那么 状态对象将通过引用共享并导致跨存储/模块 变异后的状态污染。

const fileExplorer = {
  state () {
    return {
      folderIndex: {}
    }
  },
  // mutations, actions, getters...
}

然后,在每次创建新的FileExplorer 组件时动态地register a new module,并在销毁组件之前动态地unregister that module

<template>
 <div class="container">
      <ul v-for="(item, index) in folderIndex" :key="index">
        <li>Results: {{ item.name }}</li>
      </ul>
    </div>
 </div>
</template>

<script>
import { fileExplorer } from "@/store/modules/fileExplorer";
import store from "@/store/index";

var uid = 1

export default {
  props: ["reqPath"],
  data() {
    return {
      namespace: `fileExplorer${uid++}`
    }
  },
  computed: {
    folderIndex() {
      return this.$store.state[this.namespace].folderIndex
    }
  },
  created() {
    // Register the new module dynamically
    store.registerModule(this.namespace, fileExplorer);

    // FETCH DATA FROM API
    this.$store
      .dispatch(`${this.namespace}/indexingData`, {
        reqPath: this.reqPath
      })
      .catch(error => {
        console.log("An error occurred:", error);
        this.errors = error.response.data.data;
      });
  },
  beforeDestroy() {
    // Unregister the dynamically created module
    store.unregisterModule(this.namespace);
  }
};
</script>

您不再需要在商店创建时声明的静态模块注册。

export default new Vuex.Store({
  modules: {
    // fileExplorer, <-- Remove this static module
  }
})

【讨论】:

  • 您好 Ricky,非常感谢您的详细回答,看起来很有希望。我尝试完全按照您的方式编写所有内容,但出现此错误: FileExplorer.vue?51d3:71 Uncaught TypeError: Cannot read property 'modulePath' of undefined at eval (FileExplorer.vue?51d3:71) 当我点击 eval它显示了线路制作问题是这样的:计算:{ ...mapState(this.modulePath, ["folderIndex"]) },
  • @NuoNuoLeRobot 这是有道理的,当我们调用mapState 时,我们无法访问this Vue 实例,我编辑了答案以使其工作。我看看能不能想出一个可以使用mapState的解决方案。
  • 现在我得到了这个错误:Vue warn]: Error in beforeCreate hook: "Error: [vuex] module path must be a string or an Array."不确定它是否对动态 uid 感到满意
  • 如果我 console.log(this.modulePath, uid, fileExplorer);在 beforeCreated 钩子中,我得到 undefined 1 undefined [...] 许多错误 [...] undefined 2 undefined。在我的商店模块中,我声明了 const fileExplorer : {} 但我从不导出它,这不是一个错误吗?如果是,我该如何导出它?
  • beforeCreated 生命周期钩子在数据观察之前被调用,这就是为什么它们是未定义的,我们需要改变一些东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 1970-01-01
  • 2018-08-22
  • 2019-12-14
  • 2017-10-09
  • 2020-05-18
  • 2018-01-02
相关资源
最近更新 更多