Vue: How to use component prop inside mapFields

删除回忆录丶 提交于 2019-12-05 02:07:59

问题


I have general component and vuex store. For easy two-way binding I use vuex-map-fields. On component side it has mapFields method which creates get&set with mutations. I want to pass namespace from vuex module with props but it seems to be impossible.

<my-component namespace="ns1" />

// my-component code
export default {
  props: ["namespace"],
  computed: {
    ...mapFields(??this.namespace??, ["attr1", "attr2"])
  }
}

Of course, there is no way to use this in such way so we don't have access to props. How can I specify namespace as prop in such case?


回答1:


The problem (as you probably gathered) is that computed properties are constructed before this is available, but you can get around it by deferring resolution of the this.namespace property until the computed property is called (which won't happen until component construction is finished).

The concept is based on this post Generating computed properties on the fly.

The basic pattern is to use a computed with get() and set()

computed: {
  foo: {
    get() { this.namespace...},
    set() { this.namespace...},
  }
}

but rather than type it all out in the component we can create a helper function based on the vuex-map-fields mapFields() function (see here for the original).

The normalizeNamespace() function that comes with vuex-map-fields does not support what we want to do, so we drop it and assume the namespace is always passed in (and that the store module uses the standard getField and updateField functions).

I have adapted one of the vuex-map-fields Codesandbox examples here.
Note the namespace is in data rather than props for conveniance, but props should work also.

Template

<template>
  <div id="app">
    <div>
      <label>foo </label> <input v-model="foo" /> <span> {{ foo }}</span>
    </div>
    <br />
    <div>
      <label>bar </label> <input v-model="bar" /> <span> {{ bar }}</span>
    </div>
  </div>
</template>

Helper

<script>

const mapFields2 = (namespaceProp, fields) => {
  return Object.keys(fields).reduce((prev, key) => {
    const path = fields[key];
    const field = {
      get() {
        const namespace = this[namespaceProp];
        const getterPath = `${namespace}/getField`;
        return this.$store.getters[getterPath](path);
      },
      set(value) {
        const namespace = this[namespaceProp];
        const mutationPath = `${namespace}/updateField`;
        this.$store.commit(mutationPath, { path, value });
      }
    };
    prev[key] = field;
    return prev;
  }, {});
};

export default {
  name: "App",
  data() {
    return {
      nsProp: "fooModule"
    };
  },
  computed: {
    ...mapFields2("nsProp", { foo: "foo", bar: "bar" })
  }
};
</script>

Store

import Vue from "vue";
import Vuex from "vuex";
import { getField, updateField } from "vuex-map-fields";
import App from "./App";

Vue.use(Vuex);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  modules: {
    fooModule: {
      namespaced: true,
      state: {
        foo: "initial foo value",
        bar: "initail bar value"
      },
      getters: {
        getField
      },
      mutations: {
        updateField
      }
    }
  }
});

new Vue({
  el: "#app",
  components: { App },
  store,
  template: "<App/>"
});


来源:https://stackoverflow.com/questions/54833150/vue-how-to-use-component-prop-inside-mapfields

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!