I was trying to create a signup page using my auth module in vuex. I posted an api for signing up from action in the module. When I tried this code, it said "[vuex] unknown action type: auth/signUp" in the console. Did I do anything wrong? Can anyone solve this?
This is my vuex auth module
// store/auth/index.jx
import auth from '#/API/API_Auth'
const state = () => ({})
const getters=()=>({})
const mutations = () => ({})
const actions = () => ({
signUp({commit},data){
return auth.signUp(data)
.then(res=>{
console.log(res)
})
.catch(err=>{
console.log(err)
})
}
})
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
My vuex store.
// store/index.js
import Vue from "vue";
import Vuex from "vuex"
import auth from './module/auth'
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
auth,
},
state:{},
getters:{},
mutations:{},
actions:{},
})
I imported the store and router in main.js
// main.js
import store from "./store"
import router from "./router";
new Vue({
store,
router,
render: (h) => h(App),
}).$mount("#app");
This is my sign up component where I call the action.
// src/component/signup.vue
<script>
export default {
data() {
return {
name: "",
telNumber: "",
};
},
methods: {
handleSubmit() {
let name= this.name
let telNumber= this.telNumber
this.$store.dispatch("auth/signUp", {name,telNumber})
.then(res=>{
this.$router.push({path: 'otp'});
})
.catch(err=>{console.log(err)})
}
}
}
};
</script>
Your Vuex module incorrectly sets actions, mutations, and getters as functions. Only state should be a function, and the rest should be objects:
const state = () => ({}) // ✅ function
const getters = {} // ✅ object
const mutations = {} // ✅ object
const actions = { // ✅ object
signUp({ commit }, data) {}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Related
I'm having a problem which is it gives me an error " [vuex] unknown action type: addUserAction " when I dispatch Action :-
here's my module called " HomePage "
import axios from 'axios'
export default {
state : () => ({
categories : [],
users : []
}),
mutations :{
GET_CATEGORIES( state ,categories){
state.categories = categories
},
ADD_USER(state , user){
state.users.push(user)
}
},
actions :{
getEcommCategories({commit}){
return axios.get("/api/ecommerceCategories").then(res =>{
commit('GET_CATEGORIES' , res.data.data) ;
})
},
addUserAction({commit},user){
return commit('ADD_USER' , user)
}
}
}
and this is my store :-
import Vue from "vue";
import Vuex from "vuex"
import * as HomePage from "./HomePage/home"
Vue.use(Vuex)
export default new Vuex.Store({
modules :{
HomePage
},
state,
getters,
actions,
mutations,
})
so I try to dispatch action in methods like this
add(){
this.$store.dispatch('addUserAction', this.user)
},
I think changing import * as HomePage from "./HomePage/home" to import HomePage from "./HomePage/home" in your store file might work.
Hope this helps.
add namespaced: true to your module like this:
module:
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};
root:
import customNamespace from ./customNamespace.js
modules: {
customNamespace
}
component:
this.$store.dispatch('customNamespace/action', payload)
I personally like to define everything in constants:
const NAMESPACE = 'selectOption';
const GET_SELECT_OPTIONS = 'selectOptions';
const INITIALIZE_SELECT_OPTIONS = 'initializeSelectOptions';
export const GETTER_SELECT_OPTIONS = `${NAMESPACE}/${GET_SELECT_OPTIONS}`;
export const ACTION_INITIALIZE_SELECT_OPTIONS = `${NAMESPACE}/${INITIALIZE_SELECT_OPTIONS}`;
const state = {
selectOptions: [],
};
const getters = {
[GET_SELECT_OPTIONS]: (state) => state.selectOptions,
}
const actions = {
async [INITIALIZE_SELECT_OPTIONS](context, payload) {
...
}
}
const mutations = {
...
}
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};
and then in my component i can use the action like this:
this.$store.dispatch(ACTION_INITIALIZE_SELECT_OPTIONS, payload)
or use mapActions by vuex:
methods: {
...mapActions({ initializeSelectOptions, ACTION_INITIALIZE_SELECT_OPTIONS}),
async myMethod(){
await this.initializeSelectOptions(this.payload)
}
}
i have added modules in store/index.js
import NavMessage from './nav/message/index';
new Vuex.Store({
modules: {
NavMessage,
},
});
my message/index.js
import state from './state';
import getters from './getters';
import mutations from './mutations';
export default {
state,
getters,
mutations,
};
here is getters
const getters = () => ({
getCount: state => {
return state.count;
},
});
export default getters;
i am trying to get data from NavMessage/getCount
...mapGetters({
count: 'NavMessage/getCount',
}),
but i am getting error unknown getter: NavMessage/getCount
help me thank
Below is a working example.
I've made two important changes:
I've added namespaced: true to the module.
I've removed the wrapper function from around the getters.
If you don't want to use namespacing then you'll need to change the mapGetters argument to count: 'getCount' instead. The NavMessage/ prefix is only required with namespacing.
const mapGetters = Vuex.mapGetters
const state = {
count: 6
}
const getters = {
getCount: state => {
return state.count
}
}
const mutations = {}
const NavMessage = {
namespaced: true,
state,
getters,
mutations
}
const store = new Vuex.Store({
modules: {
NavMessage
}
})
const app = new Vue({
store,
computed: {
...mapGetters({
count: 'NavMessage/getCount',
})
}
})
console.log(app.count)
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
You've tagged the question with Nuxt. If you are using Nuxt I strongly suggest reading their guide to using the store:
https://nuxtjs.org/guide/vuex-store
Nuxt does things a little differently but as far as I'm aware you still shouldn't have a function wrapper around your getters. The namespaced: true will be added automatically and you shouldn't need to create the new Vuex.Store yourself. Nuxt creates the store itself and adds modules based on the folder structure.
I am using Vue with Webpacker with Rails. I am having some problem with Vuex, specifially on using modules.
application.js:
import store from '../store/store'
Vue.prototype.$store = store;
document.addEventListener('turbolinks:load', () => {
axios.defaults.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
const app = new Vue({
el: '[data-behavior="vue"]',
store
})
})
store.js:
import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex';
import axios from 'axios';
import itemstore from'./modules/itemstore'
Vue.use(Vuex)
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
const store = new Vuex.Store({
............
modules: {
itemstore
}
})
export default store;
itemstore.js:
import axios from 'axios';
const itemstore = {
state: {
items: [],
},
actions: {
loadItems ({ commit }) {
axios
.get('/items.json')
.then(r => r.data)
.then(items => {
commit('SET_ITEMS', items);
})
}
},
mutations: {
SET_ITEMS (state, items) {
state.items = items
}
},
}
export default itemstore;
In my component:
mounted () {
this.$store.dispatch('loadItems')
},
computed: {
...mapState([
'items'
]),
}
First to get the main store imported I need Vue.prototype.$store = store;
Secondly once i move those states, actions and mutations from store.js to itemstore.js, items gets undefined. What am I doing wrong?
The namespaced setting will cause the actions, mutations and setters of a store to be namespaced based on the module name. The state of a module, however, is always separated off into its own subtree within state, even if namespacing is not being used.
So this won't work:
...mapState([
'items'
]),
This is looking for an items property in the root state.
Instead you can use something like:
...mapState({
items: state => state.itemstore.items
})
You might be tempted to try to write it like this:
...mapState('itemstore', ['items'])
However, passing the module name as the first argument to mapState will only work with namespaced modules.
I want to apply mutations through actions to a variable in my vuejs application. But I get this error saying [vuex] unknown local mutation type: updateValue, global type: app/updateValue
Here is my store folder structure:
-store
-modules
-app
-actions.js
-getters.js
-mutations.js
-state.js
-index.js
-actions.js
-getters.js
-mutations.js
-state.js
-index.js
This is my ./store/index.js file:
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import getters from './getters'
import modules from './modules'
import mutations from './mutations'
import state from './state'
Vue.use(Vuex)
const store = new Vuex.Store({
namespaced: true,
actions,
getters,
modules,
mutations,
state
})
export default store
This is my ./store/modules/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 my ./store/modules/app/actions.js:
export const updateValue = ({commit}, payload) => {
commit('updateValue', payload)
}
This is my ./store/modules/app/getters.js:
export const value = state => {
return state.wruValue;
}
This is my ./store/modules/app/mutations.js:
import { set, toggle } from '#/utils/vuex'
export default {
setDrawer: set('drawer'),
setImage: set('image'),
setColor: set('color'),
toggleDrawer: toggle('drawer')
}
export const updateValue = (state, payload) => {
state.wruValue = payload * 12;
}
This is my ./store/modules/app/state.js:
export default {
drawer: null,
color: 'green',
wruValues:1,
wruValue: 1,
}
and finally this is my vue component:
<v-btn #click="updateValue(10)">
SHOW
</v-btn>
import { mapActions } from 'vuex';
...mapActions ('app',[
'updateValue'
]),
So when I click on the button I expect to see the wruValue to change (I print the value somewhere else for testing purposes) but instead I get the error mentioned above. What's wrong with my code?
commit('updateValue', payload, {root: true})
But I find your use of namespacing odd. For my projects, I don't separate out files for getters, actions, etc, I separate out tasks, projects, companies, etc. But if it works for you, that's fine. It doesn't seem like the issue. If you still get an error, you might need to change "updateValue" to "mutations/updateValue" or something.
You should use this project structure:
src/store/modules/app.js
export const state = {
drawer: null,
color: 'green',
wruValues: 1,
wruValue: 1
}
export const mutations = {
UPDATE_VALUE: (state, payload) => {
state.wruValue = payload * 12
}
}
export const actions = {
updateValue: ({ commit }, payload) => {
commit('UPDATE_VALUE', payload)
}
}
export const getters = {
getWruValue: (state) => state.wruValue
}
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const requireContext = require.context('./modules', true, /.*\.js$/)
const modules = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)]
)
.reduce((modules, [name, module]) => {
if (module.namespaced === undefined) {
module.namespaced = true
}
return { ...modules, [name]: module }
}, {})
export default new Vuex.Store({
modules
})
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
src/App.vue
<template>
<div id="app">
<button #click="updateValue(10)">
SHOW
</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('app', ['updateValue'])
}
}
</script>
Then if you want to add a new store namespace, u need to put it inside of src/modules folder.
I am trying to verify if the user is authenticated to be able to give access to the route that is directed otherwise redirect to the login route, the problem is that I do not know how to execute the fetchUser action from my beforeEach. In other words, I can't access my getter from the router script.
store.js
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
export default {
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}
routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import routes from './rutas';
import store from '../store/';
const router = new VueRouter({
mode : 'history',
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({path: '/login'})
}
else {
store.dispatch('fetchUser') // Line error
next()
}
}
else {
next() // make sure to always call next()!
}
})
getters.js
export default {
isLoggedIn: state => {
return state.isLoggedIn
},
user_name : state =>{
if(! _.isEmpty(this.user_data))
return JSON.parse(state.user_data).name
return '';
},
isEmptyUser : state =>{
return _.isEmpty(this.user_data);
},
isAdmin: state => {
if(! _.isEmpty(this.user_data)) return state.user_data.nivel===1
return false;
}
}
actions.js
export default {
/* more methods*/
, async fetchUser({ commit }) {
return await axios.post('/api/auth/me')
.then(res => {
setTimeout(() => {
localStorage.setItem("user_data", JSON.stringify(res.data));
Promise.resolve(res.data);
}, 1000);
},
error => {
Promise.reject(error);
});
}
This returns error in console:
_WEBPACK_IMPORTED_MODULE_3__store___.a.dispatch is not a function
How can I do or the approach is the wrong one and I should not access actions directly?
The problem is your store is not the actual store object, it is just the object used to generate it.
A solution is to have the file export the real store:
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
Vue.use(Vuex); // added here
export default new Vuex.Store({ // changed here
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}) // changed here
Now your router code would work.
What you must be aware as well is that somewhere, probably in your main.js, you had the store being initialized like above. For example:
import store from '../store/';
new Vue({
store: new Vuex.Store(store),
// ...
})
Now you must remove that initialization and use the store directly:
import store from '../store/';
new Vue({
store: store, // or simply store
// ...
})
And all should be good.