Pre-fetch api data in Vuex with Nuxt.js - vuejs2

I am trying to pre-fetch some data and update Vuex before client-side kicks in.
store/index.js
export const state = () => ({});
export const getters = {};
export const actions = {
async nuxtServerInit ({ dispatch }) {
await dispatch('nasa/getImages');
}
};
store/moduleName.js
import fetch from 'node-fetch';
export const state = () => ({
images: []
});
export const mutations = {
storeImages(state, data) {
state.images = [];
state.images.push(...data);
console.log(state.images[0]); <- this logs in the terminal
}
}
export const actions = {
getImages(store) {
return fetch('api/url').then(response => {
response.json().then(function(data) {
store.commit('storeImages', data.collection.items.slice(0, 24));
});
});
}
}
My mutation gets triggered by nuxtServerInit and I am getting the first element logged in the terminal on page load. My store in the client-side however, is empty.
What am I missing?

With help from a friend we have managed to fix this issue by removing node-fetch and adding axios to Vuex instead.
The only change made was in store/moduleName.js which now looks like:
import Axios from 'axios'
export const state = () => ({
images: []
});
export const mutations = {
storeImages(state, data) {
state.images.push(...data);
}
}
export const actions = {
async getImages(store) {
let res = await Axios.get('api/url');
store.commit('storeImages', res.data.collection.items.slice(0, 24));
}
}

Related

How I can call NuxtServerInit correctly?

When i try to call rest api with nuxtServerInit on Vuex store it don't call, but if call rest api on components or page it works.
store/index.js
import axios from 'axios'
export const state = () => ({
news: [],
})
export const mutations = {
SET_NEWS(state, posts) {
state.news = posts
}
}
export const actions = {
async nuxtServerInit({ commit }, ctx) {
const res = await axios.get('https://api/news.json')
commit('SET_NEWS', res.data)
},
}
export const getters = {
getNews(state) {
return state.news
}
}
pages/news/index.vue
computed: {
getNews() {
return this.$store.getters.getNews
}
}
Try calling your API like this in your vuex actions:
export const actions = {
async nuxtServerInit({ commit }, { req }) {
const res = (await this.$axios.$get('https://api/news.json')).data
commit('SET_NEWS', res)
},
}

in Vuex, How to load state and use data from the state when the application loads/renders first ?, I am using nuxt, Vue and Vuex as store

I am trying to load data from a JSON file into the VueX store, but the state does not get loaded until I try to refresh the VueX Store manually.
what I am trying to achieve is, before the app renders, the state should be loaded with the data.
Like before I access the homepage.
But I see on the Vue Devtools, that if set it to recording mode, then the app loads the data.
Below is code from store/index.js
//store/index.js
const exec = (method, { rootState, dispatch }, app) => {
const dispatches = [];
Object.keys(rootState).forEach(async (s) => {
dispatches.push(await dispatch(`${s}/${method}`, app));
});
return dispatches;
};
export const actions = {
nuxtServerInit(store, ctx) {
console.log('nuxtServerInit');
exec('init', store, ctx);
},
nuxtClientInit(store, ctx) {
console.log('nuxtClientInit');
exec('init', store, ctx);
},
init(store, ctx) {
console.log('nuxtInit');
exec('init', store, ctx);
},
};
store/app.js
//store/app.js
export const state = () => ({
config: {},
});
export const mutations = {
SET_CONFIG(state, config) {
state.config = config;
}
}
};
export const getters = {
config: (state) => state.config,
};
const loadConfig = ({ commit }) => {
const siteConfig = require('../config/data.json');
const appConfig = JSON.parse(JSON.stringify(siteConfig.properties));
commit('SET_CONFIG', appConfig);
};
export const actions = {
init(store, ctx) {
loadConfig(store);
},
};
Here the state is empty when the app loads. How can I access that when the app loads?
I normally call the init action of my store in the layout.
When this is too late you could also do it in a plugin, I guess.
You can use the context.store in the plugin.
// plugins/init.js
export default ({ store }) => {
store.dispatch("init")
}
// store/index.js
export actions = {
init(context) {
// ...
}
}

Using Axios within nuxtServerInit()

I need to get remote data to be displayed in every pages.
This call is perfomed in store/index.js:
export const state = () => ({
contact: {
hello: "World"
}
});
export const actions = {
async nuxtServerInit({ commit, state }) {
const { contactData } = await this.$axios.get("/contact");
commit("SET_CONTACT", contactData);
}
};
export const mutations = {
SET_CONTACT(state, contactData) {
state.contact = contactData;
}
};
Problem is that the value of contact turns to undefined in the store, whereas expected content is retrieved through Axios (the retrieved content is displayed in the SSR console...)
What am I missing here?
export const actions = {
async nuxtServerInit({ commit, state }, {app} ) {
const { contactData } = await app.$axios.get("/contact");
commit("SET_CONTACT", contactData);
}
};

How do I get nuxtServerInit to dispatch an action on the Server?

I have a nuxt project using firebase. I want to use SSR and initiate and populate the store on SSR but I cannot get the code below to work.
I am working on a nuxt project I have a plugin/firebase project that initiates the firebase sdk. I have an asyncData function that works.
in my /store/index.js file I export the state function and the actions. In the actions I have the async nuxtServerInit that dispatches a `posts/getPosts' action passing the context.
In my store/index I have
export const state = () => ({})
export const actions = {
async nuxtServerInit({ dispatch }, context) {
await dispatch('posts/getPosts', context)
}
}
In my 'store/posts.js` I have
import { db } from '~/plugins/firebase'
export const state = () => ({
ActivePosts: []
})
export const actions = {
getPosts({ commit }) {
const postList = []
return db
.collection('posts')
.where('status', '==', 'approved')
.orderBy('CreatedAt', 'desc')
.get()
.then(docs => {
docs.forEach(doc => {
const newPost = doc.data()
newPost.id = doc.id
this.postList.push(newPost)
console.log(newPost)
})
})
.then(() => {
commit('addPosts', postList)
})
.catch(e => console.log(e))
}
}
In my firebase plugin I have
import firebase from 'firebase'
const firebaseConfig = {
apiKey: '<<correctkey>>.',
authDomain: '<<correctkey>>',
databaseURL: '<<correctUrl>>',
projectId: '<<correctid>>',
storageBucket: '<<correctbucket>>',
messagingSenderId: '<<correctkey>>',
appId: '<<correctkey>>'
}
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig)
}
export const db = firebase.firestore()
export const auth = firebase.auth()
This code, at least I thought, should initiate my store on the server and fill it with post values. When I check my store in vue developer tools there are no values in the store, although the getter is present and the state values(empty array) is present. This tells me that the store is initiated and the module is present, at least on the client side.
Turns out the problem was not with my action but the mutation. Here is the final code that got me to working.
import { db } from '~/plugins/firebase'
export const state = () => ({
ActivePosts: []
})
export const getters = {
getPosts(state) {
return state.ActivePosts
}
}
export const mutations = {
addPosts(state, payload) { // had to change { state } to state.
state.ActivePosts.push(payload)
}
}
export const actions = {
getPosts({ commit }) {
const postList = []
return db
.collection('posts')
.where('status', '==', 'approved')
.orderBy('CreatedAt', 'desc')
.get()
.then(docs => {
docs.forEach(doc => {
const newPost = doc.data()
newPost.id = doc.id
postList.push(newPost) //removed the `this.`
})
commit('addPosts', postList) //moved the commit to the // moved the commit out of its own then.
})
.catch(e => console.log(e))
}
}

vuex store getters not working in a component

Can anyone see why this wouldn't work please,
Trying to use vuex store to manage my axios requests and transfer to a component as follows:
In my vuex store module I have the following
import axios from "axios";
export const state = () => ({
cases: [],
})
export const mutations = {
listCases (state, cases) {
state.cases = cases;
},
}
export const actions = {
loadCases ({ commit, context }) {
return axios.get('http')
.then(res => {
const convertCases = []
for (const key in res.data) {
convertCases.push({ ...res.data[key], id: key })
}
commit('listCases', convertCases)
})
.catch(e => context.error(e));
},
export const getters = {
// return the state
cases(state) {
return state.cases
}
}
I checked amd my axios request is returning my results as expected and passing to the mutation
In my component I have
import { mapMutations, mapGetters, mapActions } from 'vuex'
export default {
created () {
this.$store.dispatch('cases/loadCases');
},
computed: {
...mapGetters ({
cases: 'cases/cases'
})
},
</script>
Now i assumed based on what I've learnt that i could call with
and this would return my items.
but i get an error cases is not defined,
Anyone abe to tell me my error please
Many Thanks
Take a look here: https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection
You may be able to make it reactive this way:
export const mutations = {
listCases (state, cases) {
state.cases = [];
cases.forEach((c) => {
state.cases.push(c);
});
},
}