Why is my Vuex state not changing after nuxtServerInit commit? - javascript

I've been using nuxtServerInit to fetch data from my contenful CMS and commit the mutation to add the data to the categories state object. However categories keeps showing empty, even when I try to render it on a component.
I can console.log the data in the mutation function and see the data, why isn't it being pushed into the categories state?
import Vuex from 'vuex'
import {createClient} from '~/plugins/contentful.js' //contentful plugin function
const client = createClient()
const createStore = () => {
return new Vuex.Store({
state: {
categories: {}
},
mutations: {
addCategories(state, data) {
state.categories += data.items
}
},
actions: {
async nuxtServerInit(context) {
client.getEntries({
content_type: 'category' //fetch everything with the content type set to category
})
.then(response => context.commit('addCategories', response))
.catch(console.error)
}
},
})
}
export default createStore

import Vue from 'vue'
import Vuex from 'vuex'
import { createClient } from '~/plugins/contentful'
const client = createClient()
export default = () => new Vuex.Store({
state: {
categories: {}
},
mutations: {
addCategories (state, data) {
Vue.$set(state, 'categories', [...data.items, ...state.catagories])
},
},
actions: {
async nuxtServerInit ({ commit }) {
let response
try {
response = await client.getEntries({ content_type: 'category' })
}
catch (error) {
console.log(error)
}
context.commit('addCategories', response)
},
})

Related

How to pass data from vuex store through module to vue component?

I'm able to console data, as well as able to see data in vuex dev tool
but not able to display them in table. Please if someone could check
my code and tell me what is wrong with it. Thanks folks. I tried differents methods like async/await, promise, getters... but I was not able to to get the data, probably I was not calling it properly.
ROLE.VUE
<emplate>
<di>
<p v-for="(role, index) in roles :key="index">
</div>
</template>
<script>
import { mapState } from 'vuex'
export default ({
name: 'Role',
metaInfo: {
title: 'Role'
},
created () {
this.$store.dispatch('loadRoles').then((response) => { console.log(response) })
},
computed: {
...mapState([
'roles'
])
}
})
</script>
role.js
import Axios from 'axios'
export default {
// namespaced: true,
state: {
roles: [],
},
getters: {
roles (state) {
return state.roles
}
},
mutations: {
SET_ROLES (state, roles) {
state.roles = roles
}
},
actions: {
loadRoles ({ commit }) {
Axios.get('/settings/roles')
.then((response) => {
console.log(response.data)
// let roles = response.data
commit('SET_ROLES', response.data.roles)
})
}
}
}
index.js
import role from './role'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
},
mutations: {
//
},
modules: {
role
},
actions: {
//
}
})
Main.js
import { store } from './store/store'
new Vue({
router,
store,
ValidationProvider,
render: h => h(App)
})
When loading from a module with mapState, you need to specify the name of the module you are loading from. Here is the proper syntax for your case:
...mapState('role', ['roles'])
The first argument is the module name, and the second is an array of state properties from that module.

vuex unknown action type while trying to post data to Django backend

I am trying to send my vuejs front end data using Vuex and Vue-axios to the backend. I have create a vuex store and vue-axios services But I get an error saying [vuex] unknown action type: addGeneral when I try to pass the data.
This is my vuex folder structure:
-store
-modules
-app
-mutations.js
-state.js
-general.js
-index.js
-actions.js
-getters.js
-index.js
-mutations.js
-state.js
This is module/general.js :
import { ApiService } from '#/services/api.service'
import { FETCH_GENERAL,
ADD_GENERAL
} from '../actions'
import { FETCH_START,
FETCH_END,
SET_GENERAL,
SET_ERROR,
} from '../mutations'
const state = {
general: [],
errors: {},
loading: false
};
const getters = {
general (state) {
return state.general;
},
isLoading (state) {
return state.loading;
}
};
const actions = {
[FETCH_GENERAL] (context, payload) {
context.commit(FETCH_START);
return ApiService
.get('general')
.then(({data}) => {
context.commit(FETCH_END);
context.commit(SET_GENERAL, data.general.results);
})
.catch(({response}) => {
context.commit(SET_ERROR, response.data.errors)
})
},
[ADD_GENERAL] (context, payload) {
context.commit(FETCH_START);
return ApiService
.postGeneral(`general`, '',payload)
.then(({data}) => {
context.commit(FETCH_END);
context.commit(SET_GENERAL, data.general.results);
})
.catch(({response}) => {
context.commit(SET_ERROR, response.data.errors)
})
}
};
const mutations = {
[FETCH_START] (state) {
state.loading = true
},
[FETCH_END] (state) {
state.loading = false
},
[SET_GENERAL] (state, pgeneral) { // can pass in payload
state.components = pgeneral;
state.errors = {}
},
[SET_ERROR] (state, errors) {
state.errors = errors
}
};
export default {
state,
getters,
actions,
mutations
}
This is module/index.js :
const requireModule = require.context('.', true, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
if (fileName === './index.js') return
// Replace ./ and .js
const path = fileName.replace(/(\.\/|\.js)/g, '')
const [moduleName, imported] = path.split('/')
if (!modules[moduleName]) {
modules[moduleName] = {
namespaced: true
}
}
modules[moduleName][imported] = requireModule(fileName).default
})
export default modules
This is store/actions.js :
export const FETCH_GENERAL = "fetchGeneral";
export const ADD_GENERAL = "addGeneral";
This is store/index.js :
import Vue from 'vue'
import Vuex from 'vuex'
// Store functionality
import actions from './actions'
import getters from './getters'
import modules from './modules'
import mutations from './mutations'
import state from './state'
Vue.use(Vuex)
// Create a new store
const store = new Vuex.Store({
actions,
getters,
modules,
mutations,
state
})
export default store
This is store/mutations.js :
export const FETCH_START = "loadingOn";
export const FETCH_END = "loadingOff";
export const SET_ERROR = "setError";
// related to general
export const SET_GENERAL = 'setGeneral';
This is my vue-axios folder structure:
-services
-api.services.js
-config.js
This is services/api.serviecs.js :
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import { API_URL } from './config'
import Cookies from 'js-cookie'
let CSRF_TOKEN = Cookies.get('csrftoken');
export const ApiService = {
init () {
Vue.use(VueAxios, axios)
Vue.axios.defaults.baseURL = API_URL
},
get (resource, slug='') {
return Vue.axios
.get(`${resource}\${slug}`,)
.catch((error) => {
throw new Error(`ApiService ${error}`)
})
},
postGeneral (resource, slug='', obj) {
return axios
.post(`${API_URL}\\${resource}\\${slug}`,{
systemName: obj.systemName,
regionOfDeployment: obj.regionOfDeployment,
operatingMode: obj.operatingMode,
solution: obj.solution,
baselineMode: obj.baselineMode,
baselineDetails: obj.baselineDetails,
projectDuration: obj.projectDuration,
},
{
headers: {
'X-CSRFToken': CSRF_TOKEN,
'Content-Type': 'application/json',
}
})
.catch((error) => {
throw new Error (`ApiService ${error}`)
})
},
}
export default ApiService
This is config.js:
export default {}
export const API_URL = 'http://127.0.0.1:8000/api';
and finally this is my vuejs component:
...
<v-btn class="mt-5 mr-2 font-weight-light" color="blue"
#click="addGeneral" >
...
methods: {
addGeneral() {
let obj = {
systemName: '',
regionOfDeployment: '',
operatingMode: '',
solution: '',
baselineMode: '',
baselineDetails: '',
projectDuration: ''
};
this.postGeneral(obj)
},
postGeneral(obj) {
this.$store.dispatch(ADD_GENERAL, obj)
}
}
Why do I get the error and what's the best way to solve it?
You're using namespaced: true, so you need to pass module name in dispatch
postGeneral(obj) {
this.$store.dispatch('general/' + ADD_GENERAL, obj)
}

Mutation committed but state not updated

I have my mutation committed, but the currentCampaign state is not updated instead returns undefined. Below is the screenshot.
This is the store.
import Vuex from 'vuex'
import Vue from 'vue'
import axios from 'axios'
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
campaigns: '',
currentCampaign: ''
},
actions: {
getCampaigns ( {commit} ) {
axios
.get('/api/campaign/history')
.then((response) => {
commit('GET_CAMPAIGNS', {campaigns: response.data});
})
}
},
mutations: {
GET_CAMPAIGNS: (state, {campaigns}) => {
state.campaigns = campaigns
},
getCurrentCampaign (state, {campaign}) {
state.currentCampaign = campaign
}
},
});
I am calling the mutation from component method like so:
methods: {
markAsCurrent (campaign) {
this.$store.commit('getCurrentCampaign', campaign.id)
}
}
What I'm not doing right here?
Thats why you are destructuring a campaign var and passing a number to the mutations, not a object.
Try this
getCurrentCampaign (state, campaign) {
state.currentCampaign = campaign
}

Vuejs and Vuex actions - Request failed with status code 422

I'm creating a system comment with Laravel 5.5, Vue 2 and Vuex.
I Can't post a comment. I get in my console, two errors:
TypeError: this.addComment is not a function
Error: Request failed with status code 422
This is my code:
import { addComment } from '../../store/actions'
export default {
computed: {
addComment
},
vuex: {
actions: { addComment }
},
data () {...},
methods: {
sendComment: function () {
this.addComment({
commentable_id: this.id,
commentable_type: this.model,
content: this.content,
reply: this.reply
})
}
actions.js code
export const addComment = function ({dispatch}, comment) {
return axios.post('/comments', comment).then((response) => {
dispatch('ADD_COMMENT', response.data)
})
};
All my routes, controller and mutations are tested and work well.
You don't need to import actions into your components as long as the store is registered globally. So you simply need to call addComment like this:
this.$store.dispatch('addComment', {
commentable_id: this.id,
commentable_type: this.model,
content: this.content,
reply: this.reply
})
Also, putting addComment in computed doesn't make sense so you have to remove it.
In your addComment action, I believe it's called commit not dispatch:
export const addComment = function ({commit}, comment) {
return axios.post('/comments', comment).then((response) => {
commit('ADD_COMMENT', response.data)
})
}
My Store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export const state = {
comments: []
};
export const mutations = {
ADD_COMMENTS (state, comments) {
state.comments.push(...comments)
},
ADD_COMMENT (state, comment) {
if (comment.reply) {
let c = state.comments.find((c) => c.id === comment.reply);
if (c.replies === undefined) {
c.replies = []
}
c.replies.push(comment)
} else {
state.comments.push(comment)
},
DELETE_COMMENT () {...}
};
let store = new Vuex.Store({
state: state,
mutations: mutations
});
export default store;
My Form.vue Component:
import { addComment } from '../../store/actions'
import { mapActions } from 'vuex'
export default {
vuex: {
actions: { addComment }
},
data () {
return {
content: '',
loading: false
}
},
props: {
id: Number,
model: String,
reply: {
type: Number,
default: 0
}
},
methods: {
sendComment: function () {
this.loading = true;
this.$store.dispatch('addComment', {
commentable_id: this.id,
commentable_type: this.model,
content: this.content,
reply: this.reply
}).catch((error) => {
this.error = error.response.data
}).then(() => {
this.loading = false
})
}
}
}

NuxtJS + Vuex — datas in the store

Using NuxtJS (a VueJS framework), I’m trying to get a bunch of datas from a REST API in a layout template (which can’t use the classic fech() or asyncData() methods).
So I'm using vuex and the nuxtServerInit() action.
This way, I should be able to gather all the datas directly during the load of the app, regardless of the current page.
But I can’t get it to work.
Here’s my map.js file for the store:
import axios from 'axios'
const api = 'http://rest.api.localhost/spots'
export const state = () => ({
markers: null
})
export const mutations = {
init (state) {
axios.get(api)
.then((res) => {
state.markers = res.data
})
}
}
export const actions = {
init ({ commit }) {
commit('init')
}
}
And the index.js (that can fire the nuxtServerInit()):
export const state = () => {}
export const mutations = {}
export const actions = {
nuxtServerInit ({ commit }) {
// ??
console.log('test')
}
}
But I can’t get it to work. The doc says:
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.
But I don’t know how I shall do this. How do I call an action defined in another module/file?
I tried to copy various example, but never got them to work ; this is the best I could come up with.
What did I missed? If needed, here’s the repo and the store folder
Thanks!
I ran into the same problem, a few weeks ago, and here is how I solved it:
======== CLASSIC MODE =========
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
import auth from './modules/base'
Vue.use(Vuex)
export default () => {
return new Vuex.Store({
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user && req.session.token) {
commit('auth/SET_USER', req.session.user)
commit('auth/SET_TOKEN', req.session.token)
}
}
},
modules: {
auth,
base
}
})
}
store/modules/auth.js
const state = () => ({
user: null,
token: null
})
const getters = {
getToken (state) {
return state.token
},
getUser (state) {
return state.user
}
}
const mutations = {
SET_USER (state, user) {
state.user = user
},
SET_TOKEN (state, token) {
state.token = token
}
}
const actions = {
async register ({ commit }, { name, slug, email, password }) {
try {
const { data } = await this.$axios.post('/users', { name, slug, email, password })
commit('SET_USER', data)
} catch (err) {
commit('base/SET_ERROR', err.response.data.message, { root: true })
throw err
}
},
/* ... */
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
Please notice the lines commit('base/SET_ERROR', err.response.data.message, { root: true }), which calls the mutation in another module (called base). And the namespaced: true option, which is required for this to work.
To learn more about namespacing in vuex modules, please refer to the documentation: https://vuex.vuejs.org/en/modules.html
======== MODULES MODE =========
The new 'modules mode' makes this much easier. You can have all the files in one folder and 'namespaced = true' is not required anymore.
Here is how the above files look in modules mode:
store/index.js
export const state = () => ({})
export const actions = {
async nuxtServerInit ({ commit }, { req }) {
if (req.session.user && req.session.token) {
commit('auth/SET_USER', req.session.user)
commit('auth/SET_TOKEN', req.session.token)
}
}
}
store/auth.js
const state = () => ({
user: null,
token: null
})
const getters = {
getUser (state) {
return state.user
},
getToken (state) {
return state.token
}
}
const mutations = {
SET_USER (state, user) {
state.user = user
},
SET_TOKEN (state, token) {
state.token = token
}
}
const actions = {
async register ({ commit }, { name, slug, email, password }) {
try {
const { data } = await this.$axios.post('/users', { name, slug, email, password })
commit('SET_USER', data)
} catch (err) {
commit('base/SET_ERROR', err.response.data.message, { root: true })
throw err
}
}
}
export default {
state,
getters,
mutations,
actions
}
To learn more about modules mode in nuxtjs, please refer to the documentation:
https://nuxtjs.org/guide/vuex-store/#modules-mode

Categories