Vue / Vuex中是否有像mapStateToProps这样的react / redux方法

时间:2018-07-31 15:52:21

标签: reactjs vuejs2 vuex

在React / Redux中映射状态和动作的常用方法如下所示,因此映射函数与组件代码分开放置:

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

import myAction from 'actions/request';

class MyComponent extends Component {
  /* BODY */
}

function mapStateToProps(state) {
  return {
    myComponentProp: state.myReducer.myReducerProp
  };
}

function mapDispatchToProps(dispatch) {
  return {
    myComponentPropAction: bindActionCreators(myAction, dispatch),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

我在Vue中找到的唯一描述状态和动作的映射方式如下

import { mapState, mapActions } from 'vuex';

export default {
  computed: {
    ...mapState('myReducer', {
      myComponentProp: (state) => state.myReducerProp,
    }),
    ...{
      /* aditional manipulations with this.myComponentProp */
    }
  },
  methods: {
    ...mapActions('myReducer', [
      'myReducerAction'
    ]),
    ...{
      myEventHandler: function() {
        /* checke conditions before action call */
        this.myReducerAction();
      },
    }
  }
}

由于扩展的数量,代码看起来很模糊,所以问题是: 是否有办法像在react / redux常规方法中一样将mapStatemapActions移动到组件外部。

感谢帮助!

1 个答案:

答案 0 :(得分:1)

好吧,除了打字稿支持外,他们还添加了一个vue-class-component装饰器,可用于实现您的目标。可以在此处找到指向此存储库的链接,但是我建议改为通过CLI创建一个新项目,然后从v3 Vue Class Component Github Repository中添加该项目开始。

<script>

function Getter (getterType) {
  return createDecorator((options, key) => {
    if (!options.computed) options.computed = {}
    options.computed[key] = function () {
      return this.$store.getters[getterType]
    }
  })
}

import Vue from 'vue'
import Component from 'vue-class-component'

    @Component({
      props: {
        propMessage: String
      }
    })
    export default class App extends Vue {
    @Getter('foo') bar
    @Setter('psu') psi

      // computed
      get computedMsg () {
        return 'computed ' + this.msg
      }

      // method
      greet () {
        alert('greeting: ' + this.msg)
      }
    }
    </script>

如您所见,正在使用此处的函数调用我们的getter和setter方法,该函数不是最佳方法,但更接近多汁的答案。现在出现了vuex-class-binding软件包,该软件包抽象了所有这些模糊的函数:vuex class

import Vue from 'vue'
import Component from 'vue-class-component'
import {
  State,
  Getter,
  Action,
  Mutation,
  namespace
} from 'vuex-class'

const someModule = namespace('path/to/module')

@Component
export class MyComp extends Vue {
  @State('foo') stateFoo
  @State(state => state.bar) stateBar
  @Getter('foo') getterFoo
  @Action('foo') actionFoo
  @Mutation('foo') mutationFoo
  @someModule.Getter('foo') moduleGetterFoo

  // If the argument is omitted, use the property name
  // for each state/getter/action/mutation type
  @State foo
  @Getter bar
  @Action baz
  @Mutation qux

  created () {
    this.stateFoo // -> store.state.foo
    this.stateBar // -> store.state.bar
    this.getterFoo // -> store.getters.foo
    this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
    this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
    this.moduleGetterFoo // -> store.getters['path/to/module/foo']
  }
}

这是一个示例,它的确非常不错,因为它能够采用命名空间模块并调用所有的getter和setter方法,而无需任何讨厌的自定义函数,因此我们可以将所有准备好使用的函数导入const以上。现在,您只需使用装饰器就可以访问所有模块功能。这与可悲地将您的功能分配到组件中的程度几乎是一样的,但是一旦完成所有设置,它看起来就很不错了。我认为可以在有或没有TS的情况下进行此操作,但我一直在TS中完成,因为它对仍相对较新的vue类组件提供了一流的支持。