I'm trying to perform a dispatch on 'logOutUser' in vuex store, and i'm getting the following error message in respone:
TypeError: Cannot read property 'dispatch' of undefined
deleteUser.vue (the component from which the dispatch action is not working):
<template>
<v-dialog v-model="openDelete" persistent max-width="500px">
<v-card>
<v-card-title>
<h4>Delete User</h4>
</v-card-title>
<v-card-text>
<h2>Are You Sure?</h2>
<p>Deleting your user is a permanent action.</p>
<br>
<br>
<v-btn
color="primary"
@click="deleteUser">
Delete User
</v-btn>
<v-btn
color="primary"
@click="openDelete = false">
Close
</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
import router from '../../router/index.js'
const firebase = require('../../firebaseConfig.js')
export default {
data: function(){
return {
openDelete: true
}
},
methods: {
deleteUser: function(){
let user = firebase.auth.currentUser
const docId = user.uid
console.log("Trying to delete user ", docId)
user.delete().then(function() {
}).catch(function(error) {
console.error("Error deleting user: ", error)
});
firebase.firestore.collection("users").doc(docId).delete().then(() => {
console.log('Trying to Log Out in Vuex')
this.$store.dispatch('user/logOutUser')
alert("User Deleted Successfully!")
}).catch(function(error) {
console.error("Error removing document: ", error);
});
router.push('hello')
this.openDelete = false
}
}
}
</script>
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import genre from './modules/genre'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
user,
genre
}
})
user.js:
const firebase=require('../firebaseConfig.js')
const state = {
currentUser: null,
userProfile: {}
}
const actions = {
fetchUserProfile({commit, state}, uid){
firebase.firestore.collection("users").doc(uid).get().then((doc)=>{
commit('setUserProfile', doc.data())
}).catch((error)=>{
console.error(error)
})
},
logOutUser({commit, state}){
commit('setCurrentUser', null)
commit('setUserProfile', {})
console.log('Logged Out In Vuex')
}
}
const mutations =
{
setCurrentUser(state, val){
state.currentUser = val
},
setUserProfile(state, val){
state.userProfile = val
}
}
export default {
namespaced: true,
state,
actions,
mutations
}
EDIT: Here's my main.js file:
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store.js'
const firebase = require('./firebaseConfig.js')
Vue.config.productionTip = false
let app
firebase.auth.onAuthStateChanged(user => {
if(!app){
/* eslint-disable no-new */
app = new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
}
});
I should mention that i'm dispatching this action from another component in my application, and it works perfectly fine from there.
Thank you!
That's because you probably didn't add store
option to the root instance of Vue. By providing it you will be able to access store from all of root's child components. Therefore your root instance should look like this:
import store from './store'
const app = new Vue({
/* .. other properties .. */
store
})
Now you can freely use this.$store
within your components.
It is unclear why it is not defined, and why it works when using modules, but not without modules. It could have something to do with the build process / transpiler. If use
is actually a static method of the Vue
class, then $store
would be shared across all instances by installing the plugin via use
, but this is not the case. It looks like Vue
should be a class exported by the Vue module, but it seems to behave like an instance.
What I've found to work is one of the following (preferred being #3):
Vue.use
wherever Vuex is usedsrc
├── App.vue
├── main.js <- Vue.use(Vuex)
├── router
│ └── index.js <- Vue.use(Vuex)
└── store
├── myModule.js
└── index.js <- Vue.use(Vuex)
// store/index.js
import Vue from "vue"; // This module's Vue is not the same instance as that referenced in main.js
import Vuex from "vuex";
import myModule from "./myModule.js";
// Required before creating new store instance
Vue.use(Vuex);
export const store = new Vuex.Store(myModule);
// main.js
import Vue from "vue"; // this module's Vue is different from store/index.js' Vue
import Vuex from "vuex";
import app from "./App";
import router from "./router/index.js";
import { store } from "./store/index.js";
// this part is essential despite already calling Vue.use in store/index.js
Vue.use(Vuex);
// Or, see alternative below
new Vue({
...,
router,
store,
components: { app }
});
$store
for all instances of Vue
(As pointed out by yukashima huksay)
src
├── App.vue
├── main.js <- Vue.prototype.$store = store
├── router
│ └── index.js
└── store
├── myModule.js
└── index.js
Vue.prototype.$store = store;
Vue
instance into store and mainsrc
├── App.vue
├── global.js
├── main.js <- Vue.use(Vuex)
├── router
│ └── index.js
└── store
├── myModule.js
└── index.js
// global.js
import vue from "vue";
export const Vue = vue;
// or if you're not using babel, you can use real javascript…,
export { Vue } from "vue";
// store/index.js
import { Vue } from "../global.js";
import vuex from "vuex";
import myModule from "./myModule.js";
Vue.use(vuex);
export const store = new vuex.Store(myModule);
// main.js
import { Vue } from "./global.js";
import store from "./store/index.js";
import router from "./router/index.js";
import app from "./App";
new Vue({
...,
router,
store,
components: { app }
});
do this
let that = this;
and use that to do the dispatching
that.$store.dispatch(action)
So i've tried all of your solutions, and nothing seems to work out for me. I started to suspect that the problem is related to the fact that deleteUser.vue is not a direct child of App.vue. Anyone I did eventually imported store directly to the component:
import store from '../../store.js'
It solved the problem. I wonder if anyone know a more efficient way to solve this problem. Thank you for your assistance!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With