this.$store is undefined following example application structure - vue.js

I'm trying to use Vuex as shown in the application structure documentation. However, $store isn't showing in Vue dev tools and returning undefined in my code. I've used the shopping cart example as a reference.
import Vue from 'vue/dist/vue';
import store from './store';
import router from './router';
const app = new Vue({
el: '#app',
store,
router,
computed: {
loading() {
return this.$store.state.application.loading.active;
}
}
});
In store/index.js (following the example layout) I have:
import Vue from 'vue';
import Vuex from 'vuex';
import application from './modules/application';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
application
}
});
And finally in store/modules/application.js:
const state = {
loading: {
active: true,
message: ''
},
syncing: {
active: false,
message: ''
}
}
const getters = {
//
}
const actions = {
//
}
const mutations = {
/**
* Update Loading
*
* #param {*} state
* #param {string} appState
* #param {boolean} active
* #param {string} message
*/
updateAppState(state, appState = false, active = false, message = '') {
if (Object.keys(state).includes(appState)) {
state.appState = {
active: active,
message: message
}
}
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Note i'm importing my router instance in a similar manor and it's working, router/index.js:
import Vue from 'vue/dist/vue';
import VueRouter from 'vue-router';
import ContentDefault from '../components/main/ContentDefault';
Vue.use(VueRouter);
export default new VueRouter({
routes: [
{
// Default view
path: '/',
components: {
default: ContentDefault
},
}
]
});
EDIT: Side issue, wasn't able to access $store in child components, it was because I was importing a different version of Vue in my main app and store files, vue instead of vue/dist/vue

You don't need the $ in your app const. And since you've just imported store you can use it directly.
Try the following:
import Vue from 'vue/dist/vue';
import store from './store';
import router from './router';
const app = new Vue({
el: '#app',
store,
router,
computed: {
loading() {
return store.state.application.loading.active;
}
}
});

Related

Why Vue doesn't see vuex?

I work with microfrontend single-spa (https://single-spa.js.org/)
I create a store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
}
})
in src/main.js i import it
import Vue from 'vue';
import singleSpaVue from 'single-spa-vue';
import 'devextreme/dist/css/dx.light.css';
import App from './App.vue';
import store from './store';
console.log("🚀 ~ file: main.js ~ line 6 ~ store", store)
Vue.config.productionTip = false;
Vue.prototype.$bus = new Vue();
const vueLifecycles = singleSpaVue({
store,
Vue,
appOptions: {
render(h) {
return h(App, {
store,
props: {
},
});
},
},
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
in console.log store displayed, but in the app cnsole.log(this) does not contain store
I don't understand where I am connecting wrong?
According to the docs, store should be a subproperty of appOptions:
const vueLifecycles = singleSpaVue({
// store, ❌
Vue,
appOptions: {
store, ✅
render(h) {
return h(App, {
// store, ❌
props: {},
})
},
},
})

Is it possible to access VueX Getters during dynamic component registration

Is it possible to access VueX store getters when defining a dynamic component using webpack?
I'm using multiple modules inside my store.
Example:
components: {
'some-template': () => {
const someVal = this.$store.getters.someVal;
return System.import(`./some-template/${someVal}.vue`)
}
}
Main.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import { someStore } from ./stores/some-store'
import { otherStore } from ./stores/other-store'
new Vue({
el: '#app',
store: new VueX.Store({
modules: {
someStore,
otherStore
}
})
})
Store example:
export const someStore = {
state: {
someVal: 'blah'
},
getters: {
someVal(state) {
return state.someVal;
}
}
}
To work around the issue with modules, I instead created an app store that will default using new Vuex instance, then dynamically add modules as needed. That way, I can import the store where needed and access the getters

Vuex. Again: Computed properties are not updated after Store changes. The simplest example

I did really read all Google!
Store property "sProp" HAS initial value (=10);
I use Action from component to modify property;
Action COMMITS mutation inside the Store Module;
Mutation uses "Vue.set(..." as advised in many tickets
Component uses mapState, mapGetters, mapActions (!!!)
I also involve Vuex as advised.
I see initial state is 10. But it is not changed after I press button.
However if I console.log Store, I see it is changed. It also is changed in memory only once after the 1st press, but template always shows 10 for both variants. All the other presses do not change value.
Issue: my Computed Property IS NOT REACTIVE!
Consider the simplest example.File names are in comments.
// File: egStoreModule.js
import * as Vue from "vue/dist/vue.js";
const state = {
sProp: 10,
};
const getters = {
gProp: (state) => {
return state.sProp;
}
};
const mutations = {
//generic(state, payload) {},
mProp(state, v) {
Vue.set(state, "sProp", v);
},
};
const actions = {
aProp({commit}, v) {
commit('mProp', v);
return v;
},
};
export default {
namespaced: true
, state
, getters
, mutations
, actions
}
And it's comsumer:
// File: EgStoreModuleComponent.vue
<template>
<!--<div :flag="flag">-->
<div>
<div><h1>{{sProp}} : mapped from Store</h1></div>
<div><h1>{{$store.state.egStoreModule.sProp}} : direct from Store</h1></div>
<button #click="methChangeProp">Change Prop</button>
<button #click="log">log</button>
</div>
</template>
<script>
import {mapActions, mapGetters, mapState} from "vuex";
export default {
name: 'EgStoreModuleComponent',
data() {
return {
flag: true,
};
},
computed: {
...mapState('egStoreModule', ['sProp']),
...mapGetters('egStoreModule', ['gProp'])
},
methods: {
...mapActions('egStoreModule', ['aProp']),
methChangeProp() {
const value = this.sProp + 3;
this.aProp(value);
//this.flag = !this.flag;
},
log() {
console.log("log ++++++++++");
console.log(this.sProp);
},
}
}
</script>
<style scoped>
</style>
Here is how I join the Store Module to Application:
// File: /src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import collection from "./modules/collection";
import egStoreModule from "./modules/egStoreModule";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {},
getters : {},
mutations: {},
actions : {},
modules : {
collection,
egStoreModule
}
});
Finally: main.js
import Vuex from 'vuex'
import {store} from './store'
//...
new Vue({
el: '#app',
router: router,
store,
render: h => h(App),
})
It all works if only I use "flag" field as shown in comments.
It also works if I jump from page and back with Vue-router.
async/await does not help.
I deleted all under node_modules and run npm install.
All Vue/Vuex versions are the latest.

vuex unknown action type when attempting to dispatch action from vuejs component

I'm using laravel, vue and vuex in another project with almost identical code and it's working great. I'm trying to adapt what I've done there to this project, using that code as boilerplate but I keep getting the error:
[vuex] unknown action type: panels/GET_PANEL
I have an index.js in the store directory which then imports namespaced store modules, to keep things tidy:
import Vue from "vue";
import Vuex from "vuex";
var axios = require("axios");
import users from "./users";
import subscriptions from "./subscriptions";
import blocks from "./blocks";
import panels from "./panels";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
actions: {
},
mutations: {
},
modules: {
users,
subscriptions,
blocks,
panels
}
})
panels.js:
const state = {
panel: []
}
const getters = {
}
const actions = {
GET_PANEL : async ({ state, commit }, panel_id) => {
let { data } = await axios.get('/api/panel/'+panel_id)
commit('SET_PANEL', data)
}
}
const mutations = {
SET_PANEL (state, panel) {
state.panel = panel
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Below is the script section from my vue component:
<script>
import { mapState, mapActions } from "vuex";
export default {
data () {
return {
}
},
mounted() {
this.$store.dispatch('panels/GET_PANEL', 6)
},
computed:
mapState({
panel: state => state.panels.panel
}),
methods: {
...mapActions([
"panels/GET_PANEL"
])
}
}
</script>
And here is the relevant code from my app.js:
import Vue from 'vue';
import Vuex from 'vuex'
import store from './store';
Vue.use(Vuex)
const app = new Vue({
store: store,
}).$mount('#bsrwrap')
UPDATE:: I've tried to just log the initial state from vuex and I get: Error in mounted hook: "ReferenceError: panel is not defined. I tried creating another, very basic components using another module store, no luck there either. I checked my vuex version, 3.1.0, the latest. Seems to be something in the app.js or store, since the problem persists across multiple modules.
Once you have namespaced module use the following mapping:
...mapActions("panels", ["GET_PANEL"])
Where first argument is module's namespace and second is array of actions to map.

Vue Router router-view error

I'm getting the following error when trying to implement vue-router.
Unknown custom element: <router-view> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Where do I need to provide the name option?
A lot of the tutorials I'm looking at seem to be an older version of vue-router. I follow the set-up process but can't get it to work.
Might there be something special I have to do when using the webpack cli template?
I'm also using the vue-router cdn.
Here's my main.js
import Vue from 'vue'
import App from './App'
import ResourceInfo from '../src/components/ResourceInfo'
var db = firebase.database();
var auth = firebase.auth();
const routes = [
{ path: '/', component: App },
{ path: '/info', component: ResourceInfo }
]
const router = new VueRouter({
routes
})
/* eslint-disable no-new */
var vm = new Vue({
el: '#app',
components: { App },
created: function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// Get info for currently signed in user.
console.log(user);
vm.currentUser = user;
console.log(vm.currentUser);
} else {
// No user is signed in.
}
})
// Import firebase data
var quizzesRef = db.ref('quizzes');
quizzesRef.on('value', function(snapshot) {
vm.quizzes = snapshot.val();
console.log(vm.quizzes);
})
var resourcesRef = db.ref('resources');
resourcesRef.on('value', function(snapshot) {
vm.resources.push(snapshot.val());
console.log(vm.resources);
})
var usersRef = db.ref('users');
usersRef.on('value', function(snapshot) {
vm.users = snapshot.val();
console.log(vm.users);
})
},
firebase: {
quizzes: {
source: db.ref('quizzes'),
asObject: true
},
users: {
source: db.ref('users'),
asObject: true
},
resources: db.ref('resources')
},
data: function() {
return {
users: {},
currentUser: {},
quizzes: {},
resources: []
}
},
router,
render: h => h(App)
})
And my App.vue
<template>
<div id="app">
<navbar></navbar>
<resource-info :current-user="currentUser"></resource-info>
<router-view></router-view>
</div>
</template>
<script>
import Navbar from './components/Navbar'
import ResourceInfo from './components/ResourceInfo'
export default {
name: 'app',
props: ['current-user'],
components: {
Navbar,
ResourceInfo
}
}
</script>
<style>
</style>
In your main.js file, you need to import VueRouter as follows:
import Vue from "vue" // you are doing this already
import VueRouter from "vue-router" // this needs to be done
And below that, you need to initialize the router module as follows:
// Initialize router module
Vue.use(VueRouter)
Other than the above, I cannot find anything else missing in your code, it seems fine to me.
Please refer to the installation page in docs, under NPM section:
http://router.vuejs.org/en/installation.html
First install vue router by using "npm install vue-route" and follow the bellow in main.js
import Vue from 'vue'
import Router from 'vue-router'
import App from './App'
import ResourceInfo from '../src/components/ResourceInfo'
var db = firebase.database();
var auth = firebase.auth();
Vue.use(Router)
var router = new Router({
hashbang: false,
history: true,
linkActiveClass: 'active',
mode: 'html5'
})
router.map({
'/': {
name: 'app',
component: App
},
'/info': {
name: 'resourceInfo',
component: ResourceInfo
}
})
// If no route is matched redirect home
router.redirect({
'*': '/'
});
// Start up our app
router.start(App, '#app')
This might be solve your problem
You forgot to import vue-router and initialize VueRouter in main.js
import VueRouter from "vue-router"
Vue.use(VueRouter)