I'm simply trying to use the store.subscribe() method in Vuex. I keep getting the following error, which seems to suggest that there is no store.subscribe method, contrary to what is in the docs:
Uncaught TypeError: WEBPACK_IMPORTED_MODULE_2__store.a.state.subscribe is not a function
this is my code:
app.js file, where I initialise everything, register my components etc:
import Vuex from 'vuex';
import router from './routes';
import store from './store';
window.Vue = require('vue');
const app = new Vue({
el: '#app',
router,
store: new Vuex.Store(store)
});
store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
my store.js file, which serves as my centralized Vuex store. It's been working perfectly until now:
import router from './routes';
export default {
state: {
sample: {
}
},
mutations: {
sample(state){
}
},
getters: {
sample(state){
return state.sample
}
}
}
how do i correct this issue
I think this happens because store is still just a regular object and not an instance of Vuex yet when you call it.
Can you try the following:
import Vuex from 'vuex';
import router from './routes';
import store from './store';
window.Vue = require('vue');
const myStore = new Vuex.Store(store)
const app = new Vue({
el: '#app',
router,
store: myStore
});
myStore.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
Add app object like app.store... because your store is not known as Vuex store instance at that level.
import Vuex from 'vuex';
import router from './routes';
import store from './store';
window.Vue = require('vue');
const app = new Vue({
el: '#app',
router,
store: new Vuex.Store(store)
});
app.$store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
Related
I'm trying to create a webapp using VUE Vite with a router and store. The getter function in the vue file works fine. I have access to the chatMessages stored in the store.js file.
My problem is that I need to call the addMessage Action from the store.js file in the dev console using the browser.
Question: How could I archive this?
On older vue versions it would be done the following way using the main.js file:
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './registerServiceWorker';
import { mapGetters, mapMutations, mapActions } from 'vuex';
Vue.config.productionTip = false;
const app = new Vue({
router,
store,
render: function (h) { return h(App) },
methods: {
...mapMutations([
'showLoading',
]),
...mapActions([
'addNotification',
]),
},
}).$mount('#app');
export default app;
Current vue3 chat.vue file:
<template>
<div></div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'Chat',
data: function() {
return {
}
},
methods: {
},
computed: {
...mapGetters({
chatMessages: 'chatMessageList',
}),
}
}
</script>
Current vue3 store.js file:
import { createStore } from 'vuex'
export default createStore({
state: {
chatMessages: {
list: [
{ type: "a", message: "test" }
]
}
},
mutations: {
addMessage(state, { type, message }) {
state.chatMessages.list.push({ type: type, message: message });
}
},
actions: {
addMessage({ commit }, { type, message }) {
commit('addMessage', { type, message });
}
},
getters: {
chatMessageList(state, getters) {
return state.chatMessages.list;
}
}
})
Current vue3 main.js file:
import App from "./App.vue";
import {createApp} from "vue";
import router from "./router/index.js";
import store from "./store/store";
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.js";
window.app = createApp(App).use(router).use(store).mount('#app');
EDIT: I tested it the following way and I can call app.addMessage from the dev console but now the router wont work.
import App from "./App.vue";
import {createApp} from "vue";
import router from "./router/index.js";
import store from "./store/store";
import { mapGetters, mapMutations, mapActions } from 'vuex';
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.js";
window.app = createApp({
methods: {
...mapActions([
'addMessage',
]),
}
}).use(router).use(store).mount('#app');
Assigning the store to the window object seems like a great approach, where you can easily then call it like in domiatorov's answer.
Another approach is:
var store = Array.from(document.querySelectorAll('*')).find(e => e.__vue_app__).__vue_app__.config.globalProperties.$store;
var actions = store._actions;
actions.addMessage[0]('mytype', 'mymessage');
The first part queries the body for an element containing __vue_app__ and will return your instance. In there, you can access config.globalProperties.$store to return your store object.
store is already available in this scope and can be exposed the same way as app:
window.store = store;
It can be used in console the same way as in an app:
store.dispatch(...)
I believe you can simply assign the store to the window object.
But do it from a top level single file component, the very first that is using the store and not in the setup to make sure the store got everything loaded.
Providing you have something like App.vue:
In setup() you would assign:
window.vueStore = store;
and use it from the console calling window.vueStore.
How would I inject vuex into Vue 3, in Vue 2 it was possible like:
new Vue({
el: '#app',
store: store,
})
But in Vue 3 how would you do it since there is no new Vue().
The created store will be injected using .use method :
import { createApp } from 'vue'
import { createStore } from 'vuex'
// Create a new store instance.
const store = createStore({
state () {
return {
count: 1
}
}
})
const app = createApp({ /* your root component */ })
// Install the store instance as a plugin
app.use(store)
For more details check the Vuex 4 docs
To use it in child component in options api, try to provide it as follows :
app.use(store)
app.config.globalProperties.$store=store;
then use it like $store in child components
for composition api (setup hook), you could just import the useStore composable function which returns the store instance :
import {useStore} from 'vuex'
setup(){
const store=useStore()// store instead of `$store`
}
Together with Router:
import * as Vue from 'vue';
import App from './App.vue';
import router from './routes';
import {store} from "./store/store";
Vue.createApp(App).use(router, store).mount('#app');
I am getting a '[vuex] unknown action type: RawHTML' when trying to dispatch an action on a component.
Those errors are usually caused by not correctly namespaced modules, but I am not using modules here.
store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const SETRAWHTML = ''
const store = new Vuex.Store({
state: {
raw:''
},
mutations: {
[SETRAWHTML](state,str){
state.raw=str
},
},
actions: {
RawHtml({commit}, str) {
commit(SETRAWHTML, str)
},
},
getters: {
getRawHTML (state) {
return state.raw
}
},
})
export default store;
main.ts
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')
my component
click(){
store.dispatch('RawHTML', this.rawHTML)
}
Thanks in advance
The name of actions is case-sensitive and you should dispatch the action with the same name as it's defined in the store, RawHTML and RawHtml don't refer to the same action, so you should respect the case and write the action dispatch as follows :
click(){
store.dispatch('RawHtml', this.rawHTML)
}
I submit the form in login.vue which will call submit(). Then I'm getting below error in the web console.
Uncaught TypeError: Cannot read property 'auth' of undefined
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import * as firebase from 'firebase/app'
import { firebaseConfig } from '#/firebaseConfig';
Vue.prototype.$firebase = firebase.initializeApp(firebaseConfig)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
login.vue
const authService = {
methods: {
submit () {
this.$firebase.auth().signInWithEmailAndPassword(this.login.email, this.login.pass).then(
(user) =>{
this.$router.replace('bm')
}
)
}
}
}
You also have to:
import 'firebase/auth'
after the firebase/app import in order to get the Firebase Auth product functionality.
Im creating a custom plugin that encapsulates a bunch of authentication functionality with vuex and vue-authenticate.
The problem im having is figuring out the correct way to load and install the module into VueJS, im not sure if its my webpack or vuejs knowledge that is lacking but so far I have the following
/node_modules/plugin/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import routes from './routes'
import store from './vuex/store'
import EventBus from './bus/eventBus'
import config from './config'
import ping from './vuex/modules/apiArchitect/ping/store'
import auth from './vuex/modules/apiArchitect/auth/store'
import user from './vuex/modules/apiArchitect/user/store'
Vue.use(Vuex)
Vue.use(EventBus)
const store = new Vuex.Store({
modules: {
ping,
user,
auth
},
strict: true
})
let apiArchitect = {}
apiArchitect.install = function (Vue, options) {
Vue.prototype.$apiArchitect = store,
Vue.prototype.$apiArchitect.$config = config
Vue.prototype.$apiArchitect.$routes = routes
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(apiArchitect)
}
}
export default apiArchitect
/src/main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import apiArchitect from 'vue-apiarchitect'
import addRouteGuards from 'vue-apiarchitect/src/addRouteGuards'
Vue.config.productionTip = false
Vue.config.env = process.env.NODE_ENV
Vue.use(router)
Vue.use(apiArchitect)
console.log(apiArchitect)
addRouteGuards(router)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
So far I am able to import the plugin and run the install hook with Vue.use(apiArchitect) I can access this.$apiArchitect in my App.vue.
The problem I have is that the plugin provides some auth routes stored in $apiArchitect.routes these routes need to be merged with the routes provided by router. If I try access $apiArchitect.routes in main.js I get an 'undefined' error I can only access them after vue has been instantiated. If I actually try console.log apiArchitect in main.js all I see is an object containing an install function none of the plugin i've provided which makes me belive its not installing correctly.
Does anyone know how i can access the apiArchitect.$routes property in main.js or a better way of achieving this?
Thanks
You can add routes dynamically with router.addRoutes() since 2.2.x.
The argument must be an Array using the same route config format with
the routes constructor option.
For example, you can use addRoutes in created hook of the root component:
// your plugin
const myPlugin = {
install: function(Vue, options) {
Vue.prototype.$myPlugin = {
routes: [{
path: '/myplugin', component: options.myComponent
}]
}
}
}
// components
const testComponent = { template: '<p>Component called by plugin route</p>' }
const Home = { template: '<p>Default component</p>' }
// router
const router = new VueRouter({
routes: [{
path: '/', component: Home
}]
})
Vue.use(VueRouter)
Vue.use(myPlugin, { myComponent: testComponent })
new Vue({
el: '#app',
router,
created() {
this.$router.addRoutes(this.$myPlugin.routes); // dinamically add routes
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<button #click="$router.push('/')">Home</button>
<button #click="$router.push('/myplugin')">Custom</button>
<router-view></router-view>
</div>