I'm using Vuex in my project with vue.js 2.0. My app.js looks like this:
import VueRouter from 'vue-router';
import Login from './components/Login.vue';
import Home from './components/Home.vue';
import VModal from 'vue-js-modal';
import Vuex from 'vuex';
import store from './store';
window.Vue = require('vue');
Vue.use(VueRouter);
Vue.use(VModal);
Vue.use(Vuex);
window.Bus = new Vue();
const routes = [
{ path: '/', component: Login, name: 'login' },
{ path: '/home', component: Home, name: 'home', beforeEnter: requireAuth },
];
const router = new VueRouter({
routes // short for `routes: routes`
});
const app = new Vue({
router,
store
}).$mount('#app');
function requireAuth() {
return this.$store.state.isLoggedIn;
}
My store looks like this:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = () => {
return new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
}
export default store;
However when I try to access a value from the state in my requireAuth function:
return this.$store.state.isLoggedIn;
or
return this.store.state.isLoggedIn;
I get the error:
Cannot read property '$store' of undefined
What could be wrong here?
--EDIT--
When I console.log(store); I see:
store() {
var _mutations;
return new __WEBPACK_IMPORTED_MODULE_1_vuex__["a" /* default */].Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
You have the function declared in the global scope like this:
function requireAuth() {
return this.$store.state.isLoggedIn;
}
So when you call this function this is bound by default to global object. But since ES6 this will be undefined instead of the global object. So you get the error cannot read $store of undefined
Since you are importing the store in app.js you can directly use:
function requireAuth() {
return store.state.isLoggedIn;
}
EDIT
export the created store instance itself, not a function that returns a store instance as follows:
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
export default store;
The requireAuth function should be:
function requireAuth() {
return store.state.isLoggedIn;
}
requireAuth is just a function defined in your app.js and this.$store is how you would refer to the store inside a Vue method. Instead, you can just refer to it in the function as store.
Related
i can't get data from Vuex,
in one component this.$store works, but in others components don't work.
Component which work perfectly is SignIn, but in HomeView and List this.$store get me error like : Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$store')
My store.js:
import { createStore } from "vuex";
const store = createStore({
state: {
logged: false,
token: "",
},
mutations: {
signIn(state) {
state.logged = true;
},
logOut(state) {
state.logged = false;
},
updateToken(state, token) {
state.token = token;
},
},
getters: {
token: (state) => state.token,
}
});
export default store;
main.js:
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";
import store from "./store/store";
import "./assets/sbx.css";
const app = createApp(App);
app.use(store);
app.use(router);
app.mount("#app");
SignIn function with this.$store
import { defineComponent, ref } from "vue";
import { signIn } from "../../services/Auth/signIn";
const userName = ref('');
const password = ref('');
async function signInUser()
{
const response = await signIn(userName.value, password.value);
if (response.status === 200) {
this.$store.commit("signIn");
this.$store.commit("updateToken", response.data.token);
}
}
export default defineComponent({
setup() {
return {
signInUser,
userName,
password,
};
},
});
And HomeView where this.$store dont work
import { defineComponent } from "vue";
const test = this.$store.getters.token;
export default defineComponent({
setup() {
return {
};
},
});
I wrote the following code but it shows an error. What is the reason for this?
Error
[vuex] unknown action type: showRegisterLogin/show
HomePage.vue // component
When using the sh method This error is caused
import { mapState, mapActions } from "vuex";
export default {
name: "HomePage",
components: {
RegisterLogin
},
data() {
return {}
},
computed: {
...mapState({
showRegisterLogin: state => state.showRegisterLogin.show
}),
},
methods: {
sh() {
this.$store.dispatch('showRegisterLogin/show');
}
}
}
/ store / modules / showRegisterLogin.js
// States
const state = {
show: false,
};
// Getters
const getter = {
show (state) {
return state.show;
}
};
// Mutations
const mutation = {
showPage (state) {
return state.show = true;
},
hidePage (state) {
return state.show = false;
}
};
// Actions
const action = {
show({ commit }) {
commit('showPage');
},
hide({ commit }) {
commit('hidePage');
}
};
export default {
namespaced: true,
state,
getter,
mutation,
action
}
/ store / store.js
'use strict';
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import showRegisterLogin from "./modules/showRegisterLogin";
export default new Vuex.Store({
modules: {
showRegisterLogin,
}
});
I also imported the store.js file into app.js and registered it in new vue
The structure of the store, module, and component are fine, except for the name of the store objects in your module:
getter should be getters
mutation should be mutations
action should be actions
Probably just typos. Those can't be arbitrarily named since Vuex looks specifically for those keys.
I have a vuex store like this:
// store.js
import Vuex from 'vuex'
import router from '../router' // this is a vuejs router
export const actions = {
async load({ dispatch, commit }) {
if (router.currentRoute.name === 'one-route') {
dispatch('oneModule/oneAction', null, { root: true })
}
}
}
export default new Vuex.Store({
state,
actions,
...
})
I would like to test it with Jest.
// store.test.js
import { createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import { actions } from './store'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
describe('store tests', () => {
let store, router, oneAction
beforeEach(() => {
oneAction = jest.fn()
const modules = {
oneModule: {
namespaced: true,
actions: { oneAction }
}
}
store = new Vuex.Store({ actions, modules })
router = new VueRouter({ routes: [{ name: 'one-route' }] })
}
test('call module action if one-route is selected', async () => {
router.push({ name: 'one-route' })
await store.dispatch('load')
expect(oneAction).toHaveBeenCalled()
})
}
This makes the following error:
Expected mock function to have been called, but it was not called.
What is the correct way to mock the router to make this test pass?
Thank you
I would like to get access to the state property currentUser of vuex in user.js to use it in auth.js but it doesn't work if I write: store.state.currentUser.uid === ...
And I get this error:
Cannot read property 'state' of undefined.
What is there missing in the code?
the tree:
src
store
user
|>user.js
|>mutations.js
index.js
auth.js
user.js:
const state = {
profile: {},
loggedIn: false,
currentUser: null,
userProfile: {}
}
export default {
namespaced: true,
state
}
auth.js:
import store from './store'
const fb = require('./firebaseConfig.js')
fb.auth.onAuthStateChanged(user => {
if (user) {
fb.postsCollection.orderBy('createdOn', 'desc').onSnapshot(querySnapshot => {
let createdByCurrentUser
if (querySnapshot.docs.length) {
createdByCurrentUser = store.state.currentUser.uid ===
querySnapshot.docChanges()[0].doc.data().userId ? 'Yes' : 'No'
console.log(createdByCurrentUser)
}
})
}
})
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from '#/store/user'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
awesome: true
},
modules: {
user
}
})
export default store
You need to use the getters, take a look in the doc
getters.js
export default {
currentUser
}
function currentUser({ currentUser }) {
return currentUser;
}
user.js
import getters from './getters'
export default {
namespaced: true,
state: {
profile: {},
loggedIn: false,
currentUser: null,
userProfile: {}
},
getters
}
auth.js
import store from './store';
const currentUser = store.getters['user/currentUser'];
Because you namespaced the module, you have to use it's name as a prefix to access the getter function
I'm trying to split up my Nuxt Vuex store files into separate files. And NOT have all Vuex getters, mutations and actions into one huge file. This demo project is on Github by the way.
I'v read this official Nuxt Vuex Store documentation; but can't seem to get it working. It's a bit vague on where to put stuff.
I have the following in these files:
Below is my: store/index.js
import Vue from "vue";
import Vuex from "vuex";
import Auth from "./modules/auth";
Vue.use(Vuex);
export const store = () => {
return new Vuex.Store({
state: {
},
modules: {
Auth
}
})
}
This is in my: store/auth.js
const state = () => {
username: null
};
const getters = {
username: state => {
return state.username;
},
isAuthenticated: state => {
return state.username != null;
}
};
const mutations = {
login: (vuexContext, username) => {
vuexContext.username = username;
this.$router.push("/dashboard");
},
logout: vuexContext => {
vuexContext.username = null;
this.$router.push("/");
}
};
const actions = {
};
export default {
state,
getters,
mutations,
actions,
};
And finally in my: pages/index.vue
This is where I'm calling that login mutation:
<script>
export default {
layout: "non-logged-in",
data() {
return {
username: null
}
},
methods: {
onSubmit() {
this.$store.commit("login", this.username);
}
}
}
</script>
The error I'm getting:
[vuex] unknown mutation type: login
What am I doing wrong here? I thought i'm importing all the stuff correctly in the store/index.js
You have to export your store constant like this inside your store/index.js file:
export default store
Put this code line at the end of your file.
So as #jeremy.raza described this is what I changed in order to get it working:
store/index.js
import Vue from "vue";
import Vuex from "vuex";
import Auth from "./modules/auth";
Vue.use(Vuex)
const store = () => {
return new Vuex.Store({
state: {
},
modules: {
Auth
}
})
}
export default store;
Changes in the store/auth.js
Note the changes in how I wrote the state, getters and mutations method notation.
const state = () => ({
username: null
});
const getters = {
username(state) {
return state.username;
},
isAuthenticated(state) {
return state.username != null;
}
};
const mutations = {
login(vuexContext, username) {
vuexContext.username = username;
this.$router.push("/dashboard");
},
logout(vuexContext) {
vuexContext.username = null;
this.$router.push("/");
}
};
const actions = {
};
export default {
state,
getters,
mutations,
actions,
};