How to modularize Vuex into different folders and files

874 Views Asked by At

I have been looking into the vuex module, then figured I could try something like creating as many modules(dir) as I want and have the action, getters, mutations and state separated into different files.

I have the vuex structure as:

.
└── src/
    ├── store/
    │   ├── moduels/
    │   │   └── todo/
    │   │       ├── state.js
    │   │       ├── getters.js
    │   │       ├── actions.js
    │   │       ├── mutations.js
    │   │       └── index.js
    │   └── index.js
    └── main.js

State

export const state =  () => {
    return {
        todos: []
    }
}

getters

export const getters = {
    allTodos: (state) => state.todos
}

actions

import axios from 'axios'
import { ALL_TODOS } from "@/store/mutation-types.js";

export const actions =  {
    async getTodos({ commit }){
        let page_url = 'https://jsonplaceholder.typicode.com/todos';
        const res = await axios.get(page_url);
        console.log(res.data);
        commit(ALL_TODOS, res.data)
    }
}

Mutations

import { ALL_TODOS } from "@/store/mutation-types.js";

export const mutations =  {
    [ALL_TODOS]: (state, todos) => state.todos = todos
}

todo/index.js

import state from './state.js';
import getters from './getters.js';
import actions from './actions.js';
import mutations from './mutations.js';

export default {
    state,
    actions,
    getters,
    mutations,
  };

store/index.js

import Vue from "vue";
import Vuex from 'vuex';
import Todo from './modules/todo';

Vue.use(Vuex)

const createStore = () => {
    return new Vuex.Store({
        namespaced: true,
        modules: {
            Todo
        }
    });
}

export default createStore

src/main.js

import store from './store/index';
new Vue({
  render: h => h(App),
  store
}).$mount('#app')

That done, if tried to use it anywhere in my code like so:

computed: {
  ...mapGetters(['allTodos'])
},
created () {
   this.$store.dispatch('todo/getTodos')
},
methods: {
 ...mapActions(['getTodos']),
}

i get an error [Vue warn]: Error in created hook: "TypeError: Cannot read property 'dispatch' of undefined"

i have also tried changing this.$store.dispatch('todo/getTodos') to this.getTodos but it won't work

Updated

so i realized there was a problem with my vue installation i re-installed it and created a new project with same structure as earlier and made some few changes to the code but still got an error [vuex] unknown action type: todo/fetchTodos

here is my code

state and getters are the same as the previous

actions.js

import axios from 'axios'
import { TODOS } from '../../mutation-type'

export const actions = {
    async fetchTodos(context){
        let page_url = 'https://jsonplaceholder.typicode.com/todos'
        const res = await axios.get(page_url);
        console.log(res.data);

        context.commit(TODOS, res.data)
    }
}

mutations.js

import { TODOS } from '../../mutation-type'

export const mutations = {
    [TODOS]: (state, todos) => state.todos = todos
}

modules/todo/index.js

import state from './state';
import getters from './getters';
import actions from './actions';
import mutations from './mutations';

export default {
    namespace: true,
    state,
    getters,
    actions,
    mutations
}

store/index.js

import { createStore } from 'vuex'
import Todo from './modules/todo';

export default createStore({
  modules: {
    Todo
  }
})

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')

and in vue file as follows:

computed: {
    ...mapGetters({
      todo: 'todo/getTodos'
    })
  },
  created(){
    this.$store.dispatch('todo/fetchTodos')
  },
  methods: {
    ...mapActions['fetchTodos']
  }
1

There are 1 best solutions below

3
On

Your store/index.js is exporting the createStore function and not the store itself. You should execute the function to get the store object in the main.js as follows:

import store from './store/index';
new Vue({
  render: h => h(App),
  store: store()
}).$mount('#app')