Vuex:具有动态名称空间的createNamespacedHelpers

时间:2019-02-08 13:54:42

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

在vuex模块注册中我看到的几乎所有指南,教程,帖子等中,如果模块由组件注册,则createNamespacedHelpers会在export default组件语句之前导入并定义,例如:

import {createNamespacedHelpers} from 'vuex'
const {mapState} = createNamespacedHelpers('mymod')

import module from '@/store/modules/mymod'

export default {
  beforeCreated() {
    this.$store.registerModule('mymod', module)
  }
}

这可以按预期工作,但是如果我们希望模块具有唯一的或用户定义的名称空间怎么办?

import {createNamespacedHelpers} from 'vuex'
import module from '@/store/modules/mymod'

export default {
  props: { namespace: 'mymod' },
  beforeCreated() {
    const ns = this.$options.propData.namespace
    this.$store.registerModule(ns, module)
    const {mapState} = createNamespacedHelpers(ns)
    this.$options.computed = {
      ...mapState(['testVar'])
    }
  }
}

我以为这样可以,但是不行。

为什么需要这样的东西? 因为

export default {
  ...
  computed: {
    ...mapState(this.namespace, ['testVar']), 
    ...
  },
  ...
}

不工作

3 个答案:

答案 0 :(得分:0)

我从veux github问题中发现了这一点,它似乎可以满足您的需求 https://github.com/vuejs/vuex/issues/863#issuecomment-329510765

using (var reader = new ResXResourceReader(AppDomain.CurrentDomain.BaseDirectory
                    + @"Properties\Resources.resx"))
                {
                    Entries = reader.Cast<DictionaryEntry>().ToList();
                    var existingResource = Entries.Where(r => r.Key.ToString().ToLower()
                    == Key.ToLower()).FirstOrDefault();
                    if (existingResource.Key == null && existingResource.Value == null)
                    {
                        Entries.Add(new DictionaryEntry() { Key = Key, Value = Value });
                    }
                    else
                    {
                        var modifiedResx = new DictionaryEntry()
                        { Key = existingResource.Key, Value = Value };
                        Entries.Remove(existingResource);
                        Entries.Add(modifiedResx);
                    }
                }
                using (var writer = new ResXResourceWriter(AppDomain.CurrentDomain.BaseDirectory
                    + @"Properties\Resources.resx"))
                {
                    Entries.ForEach(r =>
                    {
                        writer.AddResource(r.Key.ToString(), r.Value.ToString());
                    });
                    writer.Generate();
                }

...或者也许我们不需要mapXXX助手, 此评论https://github.com/vuejs/vuex/issues/863#issuecomment-439039257

中提到
{
  props: ['namespace'],

  computed: mapState({
    state (state) {
      return state[this.namespace]
    },
    someGetter (state, getters) {
      return getters[this.namespace + '/someGetter']
    }
  }),

  methods: {
    ...mapActions({
      someAction (dispatch, payload) {
        return dispatch(this.namespace + '/someAction', payload)
      }
    }),
    ...mapMutations({
      someMutation (commit, payload) {
        return commit(this.namespace + '/someMutation', payload)
      })
    })
  }
}

答案 1 :(得分:0)

这种工作方式是利用beforeCreate来访问所需的变量,我是通过传递给组件实例的props来实现的:

import { createNamespacedHelpers } from "vuex";
import module from '@/store/modules/mymod';

export default {
  name: "someComponent",
  props: ['namespace'],
  beforeCreate() { 
    let namespace = this.$options.propsData.namespace;
    const { mapActions, mapState } = createNamespacedHelpers(namespace);

    // register your module first
    this.$store.registerModule(namespace, module);

    // now that createNamespacedHelpers can use props we can now use neater mapping
    this.$options.computed = {
      ...mapState({
        name: state => state.name,
        description: state => state.description
      }),

      // because we use spread operator above we can still add component specifics
      aFunctionComputed(){ return this.name + "functions";},
      anArrowComputed: () => `${this.name}arrows`,
    };

    // set up your method bindings via the $options variable
    this.$options.methods = {
      ...mapActions(["initialiseModuleData"])
    };
  },

  created() {
    // call your actions passing your payloads in the first param if you need
    this.initialiseModuleData({ id: 123, name: "Tom" });
  }
}

我个人在导入的模块中使用辅助函数来获取名称空间,因此,如果我有我的模块来存储项目,并使用路由器和/或道具将123的projectId传递给我的组件/页面,看起来像这样:

import projectModule from '@/store/project.module';

export default{
  props['projectId'], // eg. 123
  ...
  beforeCreate() {
    // dynamic namespace built using whatever module you want:
   let namespace = projectModule.buildNamespace(this.$options.propsData.projectId); // 'project:123'

   // ... everything else as above
  }
}

希望您觉得这有用。

答案 2 :(得分:0)

所有发布的答案都只是变通办法,导致代码显得冗长且与人们在处理商店时所习惯的标准代码相去甚远。

因此,我只想让所有人都知道brophdawg11issue #863的其中一位评论者)创建了mapInstanceXXX helpers(旨在开源)解决这个问题。

也有3 blog posts系列说明了背后的原因。好读...