NuxtServerInit not working on Vuex module mode - Nuxt.js
Asked Answered
M

6

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
}
Millman answered 28/2, 2019 at 12:26 Comment(0)
D
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

Dalt answered 28/2, 2019 at 14:42 Comment(5)
Can you please give an example of how to do that.Eupatrid
@Eupatrid it is in docs and in examples. github.com/nuxt/nuxt.js/blob/…Dalt
Yes but my Vuex is in Module mode. So Kind of confused.Eupatrid
@Eupatrid the example i linked in module mode tooDalt
@Dalt Not sure if your example changed, but it does not appear to be in module mode?Frostbitten
K
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',
Keele answered 29/5, 2019 at 12:27 Comment(1)
mode: spa won't make the nuxtServerInit call. I learned this the hard way. Thank you for this comment.Overprint
A
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

Accompany answered 29/6, 2020 at 19:27 Comment(1)
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).Voyageur
B
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();
    })
  }
}
Bhakti answered 4/5, 2021 at 1:21 Comment(1)
About your new Promise with async and await. It's actually not recommended by ESLint. eslint.org/docs/rules/no-async-promise-executorShig
S
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'].

Shig answered 14/6, 2021 at 15:52 Comment(0)
B
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>
Billye answered 13/9, 2021 at 13:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.