Value in props, using in mapState can not working Vue.js - vue.js

I want to pass value from props and using it as the namespace in mapState, then it show error: 'Error while initializing app TypeError: Cannot read property 'store' of undefined'
Here my code:
ParentComponent: <Editor store="store-test" />
ChildComponent:
export default {
props: ['store'],
computed: {
mapState(`${this.store}`, ['data'])
}
}
But i replace this.store = store-test, i have receive data i want.
And i dont know how to using
...mapMutations({
function() {
}
})
is same
...mapState({
data(state) {
return state[this.store].data;
},
})

Because mapState returns its value for your computed definition at compile time, you cannot use props as they are only assigned at runtime.
You will have to use
computed: {
data () {
return this.$store.state[this.store].data
}
}
If you want, you can still use mapState however you cannot use the prop value as a namespace string
mapState({
data1 (state) { // 👈 note: cannot be an arrow function
return state[this.store].data1
},
data2 (state) {
return state[this.store].data2
}
})

Related

How to use a Nuxt component to pass a parameter to a vuex getter method? (while maintaining three dot notation)

GOAL: I would like to watch a vuex state object (MATCH_DATA) for changes, specific to the value of a prop (topicId). So, I would like to set the watcher to watch MATCH_DATA[topicId]. And whenever MATCH_DATA[topicId] updates, I'd like to call a function (in this early case just logging it).
However, since MATCH_DATA is a getter how would I pass a parameter to it? The vuex getter does not seem to be designed to take in parameters. I have seen some examples by explicitly calling this.$store.state.etc.etc. but is there a way to do this while retaining the three dot notation I currently have?
Or, is there some better way of achieving this goal that does not involve a vuex getter?
Current Code:
Nuxt component:
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
props: ['topicId'],
computed: {
...mapGetters('sessionStorage', ['MATCH_DATA']),
},
watch: {
MATCH_DATA (newMatchData, oldMatchData) {
console.log(newMatchData);
}
},
mounted() {
this.SUBSCRIBE_TO_TOPIC(this.topicId);
},
methods: {
...mapActions('sessionStorage', ['SUBSCRIBE_TO_TOPIC'])
}
}
vuex store:
/* State */
export const state = () => ({
MATCHES: {},
});
/* GETTERS */
export const getters = {
MATCH_DATA: (state) => {
return state.MATCHES;
},
};
Your getter can simply return a function like this:
export const getters = {
MATCH_DATA: (state) => {
return topicId => {
// return something
}}
},
};
Then you can create a computed property to access those getter:
export default {
computed: {
...mapGetters('sessionStorage', ['MATCH_DATA']),
yourComputedProperty () {
return this.MATCH_DATA(this.topicId)
}
}
}
Then you can watch the computed property to react on changes.
watch: {
yourComputedProperty (newData, oldData) {
console.log(newData);
}
}

Vuex: importing a single state from an object

I have a simple store:
UsersStore.js
state() {
return {
users: {
name: '',
userHasPermissions: false,
}
}
}
I am trying to use mapState to have the state accessible in my component. When I import the entire User object of the store like below, it works:
App.vue
computed: {
...mapState('users', {
myUser: 'user'
}
but I just want to import the userHasPermissions state but when I do the following, it does not seem to work:
App.vue
computed: {
...mapState('users', {
hasPerms: 'user.hasPermissions'
}
You can use vuex getters to get a specific property from any store object
state() {
return {
users: {
name: '',
userHasPermissions: false,
}
}
},
getters: {
userHasPermission(state) {
return state.users.userHasPermission || false;
}
}
Now you can use mapGetters to map store getters to your vue component
computed: {
...mapGetters({
hasPerms: "userHasPermission"
})
}
If you want to avoid using mapGetters and getters and use mapState, then you need to define a computed function inside your mapState to fetch the desired property
computed: {
...mapState({
hasPerms: (state) => state.users.userHasPermission
})
}

VueX actions/mutations error in Chrome console

I try to store drawer data in VueX to use it on external component.
My console error: [vuex] unknown action type: app/switchDrawer
My VueJS template:
pages/test.vue
<template>
<v-navigation-drawer v-model="drawer" app>
<v-list dense>
...
</v-list>
</v-navigation-drawer>
</template>
<script>
export default {
computed: {
drawer: {
get () {
return this.$store.state.app.drawer
},
set (value) {
console.log(value);
return this.$store.dispatch('app/toggleDrawer', value)
}
}
}
}
</script>
The console.log() function give me lot of lines in loop in console.
I'd like to use too the mapGetters class from VueX instead computed get/set:
computed: mapGetters({
drawer: 'app/drawer'
})
I've an error in console:
[Vue warn]: Computed property "drawer" was assigned to but it has no
setter.
My VueX store:
store/app.js
export const state = () => ({
drawer: true
})
export const getters = {
drawer: state => state.drawer
}
export const mutations = {
TOGGLE_DRAWER: (state) => {
state.drawer = !state.drawer
}
}
export const actions = {
toggleDrawer ({ commit }, value) {
commit('TOGGLE_DRAWER', value)
}
}
IN CASE YOU DON'T WANT TO MAKE A NEW MUTATION AND HANDLE LOCALLY. (which I preferred personally as my store is pretty big already)
Faced similar issue using when using a vue-ui library(vuesax)
Solved it by initializing a new data variable to a computed variable (the one from the store) in created hook
(Why in created hook)
created() {
this.localDrawer = this.drawer
},
data() {
return {
localDrawer: ''
}
},
computed: {
...mapGetters({
drawer: 'drawer'
})
},
watch: {
drawer(newValue, oldValue) {
this.localDrawer = newValue
}
}
Now use localDrawer in the you app.
NOTE: I am watching the drawer variable as well. So that in any case if its value changes it gets reflected.
Found your problem - a computed setter has to have no return statement.
drawer: {
get () {
return this.$store.state.app.drawer
},
set (value) {
this.$store.dispatch('app/toggleDrawer', value)
}
}
Please notice that your action submits a value to the mutation which dosen't take any value. So better add a new mutation that handles said value:
export const mutations = {
SET_DRAWER: (state, value) => {
state.drawer = value
}
}
export const actions = {
toggleDrawer ({ commit }, value) {
commit('SET_DRAWER', value)
}
}

Why I commit to set the state's data to null, the component state do not change util I refresh the page?

In my store.js:
state: {
...
user_info: LocalStorageUtil.get('user_info')
},
mutations: {
set_user_info_null(state){
state.user_info = null
}
}
In my component:
// in the template
<div v-if="user_info" class="welcome">
<a #click="welcome_username">欢迎您,{{user_info.username}}!</a>/<a #click="logout">退出</a>
</div>
// in the script
data(){
return {
user_info: this.$store.state.user_info,
...
}
methods: {
...
... // in the logout method
LocalStorageUtil.clear('user_info')
this.$store.commit('set_user_info_null') // store set to null
You see, I clear the user_info first, and then Vuex to commit set_user_info_null. The Vuex's state user_info will be set to null.
but however, in the Component's data the user_info still is the Object:
EDIT -1
If I use the code:
import { mapState } from "vuex";
export default {
computed: {
...mapState("user_info")
}
};
I got a error:
TypeError: undefined is not an object (evaluating 'Object.keys(map)')
in this line:
computed: {
...mapState("user_info")
},
components: { // in this line
...
This part is problematic in your component
data(){
return {
user_info: this.$store.state.user_info,
...
}
You are declaring a local component state that is separated from the Vuex store. When you update Vuex store, this won't change.
The right way is by using mapState
import { mapState } from "vuex";
export default {
computed: {
...mapState(["user_info"])
}
};
It would be like you are passing user_info as a prop to this component. When Vuex store is updated, this component will be updated as well.
In the newer( higher than v.2.3.4 ) version Vue.js the code will check the set, if in your code has this.user_info=xxx :
You can check the source code.
So, first I will recommend you change the this.$store.state.user_info=xxx replace of this.user_info=xxx.
Second you should take a look at the Two-way Computed Property
computed: {
message: {
get () {
return this.$store.state.user_info
},
set (value) {
this.$store.commit('set_user_info_null')
}
}
}

Write a Global Methods to check authentication in NuxtJS

I have difficulty to Write a Global Methods to check authentication in NuxtJS. The methods which I can write v-if in components to display if it return True.
I put this code in layout/default.vue but it doesn't works.
/layout/defaut.vue
<script>
import '~/assets/icons'
export default {
head () {
return !this.mobileLayout ? {} : {
bodyAttrs: {
class: 'mobile'
}
}
},
created () {
this.LoggedIn()
},
methods: {
LoggedIn: function () {
return this.$store.state.authUser
}
}
}
</script>
Components:
<template>
<div v-if="LoggedIn">Authenticated</div >
</template>
Error:
Property or method "LoggedIn" is not defined on the instance but referenced during render
Hope you guy help me!
Since authUser is a state property in vuex, not a method. LoggedIn in your component is simply returning a value from the state and does not need to be a method.
You should use a computed instead of a method. You also do not need to call LoggedIn from the created method, once it is a computed, it will be calculated automatically.
<script>
import '~/assets/icons'
export default {
head () {
return !this.mobileLayout ? {} : {
bodyAttrs: {
class: 'mobile'
}
}
},
computed: {
LoggedIn: function () {
return this.$store.state.authUser
}
}
}
</script>
Or even better, use mapState from vuex which is documented here https://vuex.vuejs.org/en/state.html
<script>
import Vuex from 'vuex'
import '~/assets/icons'
export default {
head () {
return !this.mobileLayout ? {} : {
bodyAttrs: {
class: 'mobile'
}
}
},
computed: {
...mapState({
LoggedIn: 'authUser'
})
}
}
</script>
Your template does not need to be changed.