13

NuxtServerInit is not working on initial page render on nuxt js vuex module mode. But it works on Classic mode. Following code is the flow I used.

My api call

api/CategoryApi.js

import axios from 'axios';

const HEADERS = {
    Accept: 'application/json'
};

export default {
    getCategory(payload) {
        return axios.get(`${process.env.apiUrl}/category`, {
            payload,
            headers: HEADERS
        });
    }
}

store/modules/CategoryStore.js

import api from '~/api/CategoryApi'

const state = () => ({
    categories: []
});

const getters = {
    allCategories: state => state.categories
};

const actions = {
    async nuxtServerInit({commit}) {
        const payload = {
            per_page: 6,
            page: 1
        };
        const response = await api.getCategory(payload);
        commit('setCategories', response.data.data);
    },
};

const mutations = {
    setCategories: (state, data) => {
        state.categories = data;
    }
};

export default {
    state,
    getters,
    actions,
    mutations
}

pages/index.vue

<template>
    <div>
        <v-flex xs6 sm4 md2 class="text-xs-center my-2 pa-2" v-for="category in allCategories" :key="category.id">
            {{ category.name }}
        </v-flex>
    </div>
</template>

<script>
    import { mapGetters } from 'vuex';

    export default {
        layout: 'default',
        computed: {
            ...mapGetters({
                allCategories: 'modules/CategoryStore/allCategories',
            })
        },
    }
</script>

Am I doing this wrong? :/ I want to know the right way to implement this.

Edit: How I did with Aldarund answer (This might help someone)

Edited store/modules/CategoryStore.js

const actions = {
    async fetchCategories({commit}) {
        const payload = {
            per_page: 6,
            page: 1
        };
        const response = await api.getCategory(payload);
        commit('setCategories', response.data.data);
    },
};

Added store/index.js

const actions = {
    async nuxtServerInit({dispatch}) {
        await dispatch('modules/CategoryStore/fetchCategories');
    },
};

export default {
    actions
}
Manikandan
  • 502
  • 1
  • 7
  • 17

6 Answers6

16

As said in the docs

If you are using the Modules mode of the Vuex store, only the primary module (in store/index.js) will receive this action. You'll need to chain your module actions from there.

So you need to place your nuxtServerInit into store/index.js

Aldarund
  • 17,312
  • 5
  • 73
  • 104
4

try use that code, clear file index.js, and run.. on server console you see message.

     export const actions = {

  nuxtServerInit ({ dispatch }) {
    console.log("troololollo")
  }
}

maybe also can try nuxt.config.js

module.exports = {
  //mode: 'spa',
  mode: 'universal',
blst
  • 61
  • 3
  • 2
    `mode: spa` won't make the nuxtServerInit call. I learned this the hard way. Thank you for this comment. – tbone Mar 06 '20 at 15:54
2

It's not true that you can only call nuxtServerInit from within store/index.js

I think what confused me most was the difference between the modular approach and only having a single store file. In the latter approach, I would do something like:

nuxtServerInit(vuexContext, {req, redirect, params})
    {
      vuexContext.dispatch('someAction',someArguments)
    }

Whereas when calling in a module, for example store/modules/auth.js, you cannot use the vuexContext, but instead use dispatch directly:

nuxtServerInit({dispatch})
        {
          dispatch('someAction',someArguments)
        }

This worked for me, hope it helps

  • hey Andre, when you just want to indicate that it's code, you can use the "pre-code" formatting ({} icon) instead of the executable snippet formatting (<> icon). – LShapz Jun 29 '20 at 21:41
0

So many answers to these questions referencing the docs, but none mention how to actually "chain your module actions from [index.js]."

posts.js

export const actions = {
  // This isn't called unless it is "chained"
  nuxtServerInit(vuexContext, context) {
    return new Promise((resolve, reject) => {
      // do a thing
      resolve()
    })
  },
}

index.js

import { actions as postActions } from './posts' ;

export const actions = {
  nuxtServerInit(vuexContext, context) {
    return new Promise(async (resolve, reject) => {
      // "chain" the desired method
      await postActions.nuxtServerInit(vuexContext, context)
      resolve();
    })
  }
}
Mrweiner
  • 481
  • 1
  • 8
  • 23
  • About your new Promise with async and await. It's actually not recommended by ESLint. https://eslint.org/docs/rules/no-async-promise-executor – Morgan Koh Jun 15 '21 at 15:18
0

I've spend quite some time on this problem. I'll try to summarise my findings here with sample code to solve this issue once and for all.

Yes, the documentation from NuxtJS did said that once you structure your Vuex into modules. Then, your module's nuxtServerInit won't be called.

Unless you trigger it on store/index.js.

https://nuxtjs.org/docs/2.x/directory-structure/store#the-nuxtserverinit-action

Previously, our Vuex structure is like this.

store/modules/user.js
store/modules/todo.js
store/index.js

So, you will initialise the modules in your index.js and for the new module way moving forward into Vue 3. You'll still need index.js to trigger your nuxtServerInit.

New Vuex structure for the module approach is like this.

store/user.js
store/todo.js
store/index.js

Yes, you just need to take it our from your module package and move it to your store package.

Alright now, let's trigger todos.nuxtServerInit from store/index.js.

'/store/index.js'
import todos from './todos'

const state = () => ({})
const getters = {}
const mutations = {}

const actions = {
  async nuxtServerInit(vuexContext, context) {
    await Promise.all([
        todos.actions.nuxtServerInit(vuexContext, context)
    ])
  },
}

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

Now, inside store/todos.js.

'/store/todos.js'

...

const actions = {
  async nuxtServerInit(vuexContext, context) {
    return await vuexContext.commit('todos/setTodos', todos)
  },
}

...

Remember to use vuexContext.commit('todos/setTodos', todos) if you're previously calling like vuexContext.commit('setTodos', todos).

Because now your module is at the store package, and NuxtJS generated all the package imports for you already.

Just be aware of how your this.$store.getters as well, because it's now also restructured like this this.$store.getters['todos/todos'].

Morgan Koh
  • 2,297
  • 24
  • 24
0

Could you not do it like this ...

index.js

export default {
    state: () => ({
        context: undefined
    }),

    actions: {
        nuxtServerInit ({ state }, ctx) {
            state.context = () => ctx;
        }
    }
};

Then call it from other Stores like this ...

rootState.context().<some object hanging off of the context>
Billy
  • 83
  • 1
  • 8