Vuex store getter empty - vue.js

I'm following the sample code in the Vuex guide and I'm getting a weird result (at least for me).
Vuex Store
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
name: ""
},
mutations: {
updateName(state, newName) {
state.name = newName;
}
},
getters: {
getName: state => state.name
}
});
export default store;
Component, inside the <script> tags:
import { mapGetters } from "vuex";
export default {
name: "Home",
data: function() {
return {
showingName: true
};
},
computed: {
...mapGetters(["getName"])
},
methods: {
getNameHandler() {
// eslint-disable-next-line
console.log(this.$store.getters.getname); // returns undefined
}
}
};
Here is a live sample:
https://codesandbox.io/s/yww774xrmj
Basically the question is, why the console.log returns undedined?. you can see that by clicking the button in the Home component. I'm following the same pattern as shown in the official Vuex guide:
https://vuex.vuejs.org/guide/getters.html#property-style-access
Unless I'm missing an import or a Vue.use(), but what gets my attention is that using the ´mapGetters´ actually allows me to use the getter as a computed property. You can change the name property of the state with the button in the About component.

The getter name is case-sensitive.
this.$store.getters.getName
You have
this.$store.getters.getname

First of all install the chrome plugin for vuex link.
Please check your mutations -> updateName is updating the state or not then you will get you're value from getters -> getName.
I hope that gonna help you out.
Thanks.

Related

Vuex access states in actions weird

I have a Vuex store like this. When triggering the storeTest action from my component with this.$store.dispatch("storeTest"); I need to use this weird syntax store.store to access an item.
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
loading: false,
fileStr: "data.json",
},
actions: {
storeTest(state) {
//works
console.log("state: ", state.state.fileStr);
//fail
console.log("state: ", state.fileStr);
},
},
},
});
I would expect I can access a state with state.item. Instead I have to write state.state.item. What could be wrong?
It's because actions do not receive state as a parameter, but context. You need it to dispatch other actions or to commit.
actions: {
async myAction ({ state, dispatch, commit }) {
console.log(state.loading);
await dispatch('anotherAction')
commit('someCommit')
}
}
Full list of the context properties here.
The first argument to an action function is not state, rather context (see docs).
This "context" object has various properties, one of which is state.
This differs from a mutation where the first argument is state.
refined and working thanks to #FitzFish
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
loading: false,
fileStr: "data.json",
},
actions: {
storeTest(context) {
//works
console.log("state: ", context.state.fileStr);
},
},
});

Vuex: How to update component data or call component methods from Store

If I have a store:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
foo: bar
},
mutations: {
updateComponent (state) {
// computation and logic
// update state
this.$refs.myComponent.updateComponent(state.foo)
}
}
}
And I have a component with ref 'myComponent':
<template>
...
</template>
<script>
export default {
...
methods: {
updateComponent(payload) {
// do stuff
}
}
}
</script>
I would like to call the 'updateComponent()' method from the store. I can use this.$refs.myComponent from other views and components, but it doesn't work from the Store. I get error TypeError: Cannot read property 'myComponent' of undefined.
Clearly this is not the correct scope for the this.$refs.myComponent when using from the Store.
Can I call updateComponent() from my store mutation, and how?
You could use vuex's subscribe method. Subscribe your component in it's mounted phase:
mounted() {
this.$store.subscribe((mutation, state) => {
switch(mutation.type) {
case 'updateComponent':
// Update your component with new state data
break;
}
})
}
Reference: https://vuex.vuejs.org/api/#subscribe

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.

How to watch two more stores in Vue.js and Vuex?

I'm using Vue.js and Vuex.
I want to watch the value of store (I'll share my sample codes in the last of this post).
But I have encountered the error "Error: [vuex] store.watch only accepts a function."
In this Web site, I found how to use "single" store.
https://codepen.io/CodinCat/pen/PpNvYr
However, in my case, I want to use "two" stores.
Do you have any idea to solve this problem.
●index.js
'use strict';
import Vue from 'vue';
import Vuex from 'vuex';
import {test1Store} from './modules/test1.js';
import {test2Store} from './modules/test2.js';
Vue.use(Vuex);
export const store = new Vuex.Store({
modules: {
test1: test1Store,
test2: tes21Store,
}
});
●test1.js
'use strict';
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const checkerStore = {
namespaced: true,
state: {
count: 1
},
getters: {
getCount(state){
return state.count;
}
}
};
export default {test1};
●test.vue
<template>
{{ $store.state.couunt }}
</template>
<script>
import {store} from './store/index.js';
export default {
data: function () {
return {
}
},
store: store,
methods: {
},
mounted() {
setInterval(() => { this.$store.state.count++ }, 1000);
this.$store.watch(this.$store.getters['test1/getCount'], n => {
console.log('watched: ', n)
})
}
}
}
</script>
You're getting that error because in your example code, the first argument you've passed to watch is, as the error suggests, not a function.
The argument is actually implemented using the native JavaScript call Object.defineProperty underneath the hood by Vue, so the result of doing store.getters['test1/getCount'] as you have, is actually a number.
I don't think it's recommended to use watch in a scenario like yours, but if you insist, you can access count by providing an alternate argument form, something like:
this.$store.watch((state, getters) => getters['test1/getCount'], n => { ... })