Search code examples
vue.jsnuxt.jsvuex

How to properly use store in vue/nuxt?


I am using vue/vuex with nuxt.js and getting some errors. I think its just a naming issue but I cannot figure out why:

// ./store/dates.js

import * as types from './types'

const actions = {
  [types.DATES_FILTER_START]: ({ commit }, opts) => {
    debugger
    commit(types.DATES_FILTER_START, opts.filterStartDate)
  },

  [types.DATES_FILTER_END]: ({ commit }, opts) =>
    commit(types.DATES_FILTER_END, opts.filterEndDate),
}

const mutations = {
  [types.DATES_FILTER_START]: (state, filterStartDate) => {
    debugger
    state.filterStartDate = filterStartDate
  },
  [types.DATES_FILTER_END]: (state, filterEndDate) => {
    debugger
    state.filterEndDate = filterEndDate
  },
}

const getters = {
  [types.DATES_FILTER_START]: (state) => state.filterStartDate,
  [types.DATES_FILTER_END]: (state) => state.filterStartEnd,
}

export const state = () => ({
  filterStartDate: '',
  filterEndDate: '',
})

export default {
  state,
  getters,
  mutations,
  actions,
}
// store/types.js

export const DATES_FILTER_START = 'dates/FILTER_START'
export const DATES_FILTER_END = 'dates/FILTER_END'

I get the following errors:

[vuex] unknown getter: dates/FILTER_END vuex.esm.js:1023
[vuex] unknown getter: dates/FILTER_START vuex.esm.js:1023
[vuex] unknown getter: dates/FILTER_END
...
[vuex] unknown action type: dates/FILTER_START

Here is how I'm trying to use the store:

<template>
  <div>
    <h4>Date Range</h4>
    <div class="grid date-range control">
      <div class="span-6">
        <label for="start-date">Start date</label>
        <input
          id="start-date"
          type="date"
          :min="minDatePickerDate"
          :value="filterStartDate"
          @change="setFilterStartDate"
        />
      </div>

      <div class="span-6">
        <label for="end-date">End date</label>
        <input
          id="end-date"
          type="date"
          :min="filterStartDate"
          :value="filterEndDate"
          @change="setFilterEndDate"
        />
      </div>
    </div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import * as types from '../../store/types'

export default {
  data() {
    return {
      minDatePickerDate: '2015-01-01',
    }
  },
  computed: {
    ...mapGetters({
      filterStartDate: types.DATES_FILTER_START,
      filterEndDate: types.DATES_FILTER_END,
    }),
  },
  methods: {
    ...mapActions({
      setFilterStartDate: types.DATES_FILTER_START,
      setFilterEndDate: types.DATES_FILTER_END,
    }),
    // ...mapMutations({
    //   setFilterStartDate: types.DATES_FILTER_START,
    //   setFilterEndDate: types.DATES_FILTER_END,
    // }),
  },
}
</script>

I've added an empty ./store/index.js like the docs say


Solution

  • An empty store/index.js is not necessary.

    Every js file in the store directory is automatically transformed into a namespaced module, so store/dates.js creates a module named "dates". store/types.js is not intended to be a module, so its filename should be prefixed with the ignorePrefix pattern (default of -):

    store/types.js  // ❌ creates a module
    
    store/-types.js // ✅ ignored
    

    Since dates is a namespaced module, your mapGetters, mapActions, and mapMutations calls must include the namespace ("dates") as the first argument:

    import { mapGetters, mapActions } from 'vuex'
    import * as types from '~/store/-types'
    
    export default {
      computed: {        👇
        ...mapGetters('dates', {
          filterStartDate: types.DATES_FILTER_START,
          filterEndDate: types.DATES_FILTER_END,
        }),
      },
      methods: {         👇
        ...mapActions('dates', {
          setFilterStartDate: types.DATES_FILTER_START,
          setFilterEndDate: types.DATES_FILTER_END,
        }),                👇
        ...mapMutations('dates', {
          setFilterStartDate: types.DATES_FILTER_START,
          setFilterEndDate: types.DATES_FILTER_END,
        }),
      },
    }
    

    demo 1

    Alternatively, you could disable the namespacing for store/dates by exporting namespaced=false:

    // store/dates.js
    export default {
      namespaced: false,
      //...
    }
    

    demo 2

    You should be aware that your component has a data binding issue for the end date, but that's beyond the scope of the original question.