Search code examples
typescriptvue.jsvuejs2storevuex

can't access getters in store module


This is the definition of my store module.

// rest defined above
const _GETTERS = {
  getName: state => {
    return state.current.name;
  },
  getLastName: state => {
    return state.current.lastName;
  },
  getFullName: (state, getters) => {
    // return `${state.current.name} ${state.current.lastName}`;
    return `${getters.getName()} ${getters.getLastName()}`;
  },
  getMailAddress: state => {
    return state.current.mailAddress;
  }
};

const UsersStore = {
  ...
  getters: _GETTERS
};

The above is my user-store module and I get a Uncaught TypeError: getters.getName is not a function ERROR. When I change the code to use the version which accesses the state instead of the getters, everything works fine. Below is the main store object where I add the above as a module.

export default new Vuex.Store({
  strict: process.env.NODE_ENV !== 'production',
  state: _state,
  getters: _getters,
  actions: _actions,
  mutations: _mutations,
  modules: {
    users: UserStore
  }
});

This is where it should be rendered and it works just fine when accessing the store directly instead of using the getters.

import {Component, Vue} from 'vue-property-decorator';
import {mapGetters} from 'vuex';

const template = require('./app-footer.vue').default;

@Component({
  mixins: [template],
  computed: {
    ...mapGetters({
      name: 'getFullName'
    })
  }
})
export default class AppFooter extends Vue {
}

Solution

  • Problem

    Here's your error:

    Uncaught TypeError: getters.getName is not a function

    Here's your code:

    getFullName: (state, getters) => {
      return `${getters.getName()} ${getters.getLastName()}`;
    },
    

    The error is thrown because you are trying to call getters.getName as a function (getters.getName()) when it is not a function.

    You can compare that with the case where you report no error being thrown:

    getFullName: (state, getters) => {
      return `${state.current.name} ${state.current.lastName}`;
    },
    

    You are accessing state.current.name as a property – not calling it as a function.

    See Vuex's getter documentation for guidance on using getters.

    Solution

    Stop attempting to call getters.getName as a function by removing the unneeded parentheses.

    Notes

    Why is getters.getName not a function? It looks like defined it as a function. Look at this example at the docs – doneTodos is a function, right?

    getters: {
      doneTodos: state => {
        return state.todos.filter(todo => todo.done)
      }
    }
    

    https://vuex.vuejs.org/en/getters.html

    The methods that you define on the getters object are set as getters on the store object. Getters allow you to access dynamically computed values as if they were a property (ie without a function call).

    Sometimes it is desirable to allow access to a property that returns a dynamically computed value, or you may want to reflect the status of an internal variable without requiring the use of explicit method calls. In JavaScript, this can be accomplished with the use of a getter. It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value, although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property.

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

    See the MDN doc for how getters are defined and used.

    VueJS takes your methods defined on the getters object and uses Object.defineProperty to define getters on the store object which in turn lets you access dynamically computed properties. If you are familiar with VueJS's computed properties, the behaviour and usage is basically the same.

    Further reading