Don't understand how to use mapState from the docs

Hi Vuesters!

Sooo…trying to figure out how to use VueX proficiently, and I’m a little stuck on mapState.

I get that I can have data in VueX, like so:

state: {
   name: 'person'
}

…and access that piece of data in a .vue file component, like so:

computed: {
    name () {
        return this.$tore.state.name
    }
}

But I have two or more separate pieces of data in a VueX store, like so:

state: {
   name: 'person',
   age: 'nunya business'
}

…I would need to have a separate computed property for age as well, like so:

computed: {
    name () {
        return this.$tore.state.name
    },
    age () {
        return this.$tore.state.age
    }
}

…which will get verbose fast as more pieces of data are added to the computed pile.

So, I have this sense that mapState is what to use to cut down on extra code and typing and stuff, but I just don’t get what is going on from the example in the VueX docs.

So, if I have, let’s say, 3 piece of data, like so:

state: {
   name: 'person',
   age: 'nunya business',
   job: 'codez n stuffz'
}

…how do I go about using mapState to access all 3 (or more, honestly) pieces of data…or is there a better way of doing that sort of thing that I am unaware of…

thanks! XD

3 Likes

mapState simply maps store members, as component members for easy access. For example a component.

computed: {
  ...mapState('module/1A', ['name', 'age', 'job'])  // assuming you are using namespaced modules
},
methods: {
   testFn () {
      console.log(this.name)
   }
}

So as you can see, I can now access store members on my component much easier in my testFn method. You can also use them in your template like you normally would with any data () member or computed property

7 Likes

hmmmm…so would I then do something like this in the template?

<template>

    <h1>{{ 1A.name }}</h1>
    <h2>{{ 1A.age }}<h2>
    <p>{{ 1A.job  }}</p>

    <h1>{{ 1B.name }}</h1>

    etc...

</template>

…to access the data from each module, if need be?

Here is the last question in a real world scenario…

Could I do this:

computed: {
  ...mapState('module/authors', ['name', 'age', 'job']);
  ...mapState('module/articles', ['title', 'subtitle', 'image'])
}

…to then be able to do this:

<template>

    <h1>{{ article.title }}</h1>

    <p>{{ author.name }}</p>

    etc...

</template>

This is generally what I am trying to do. Have a centralized static data store and then feed the app whatever data it needs wherever it needs it. Not trying to mutate state just yet. Just trying to move data around and access from anywhere, but have one ‘source of truth’ for all data.

And for this use case of ‘static data’, do I need to use getters or mutations or actions at all? Or would they be overkill for this use case?

I hope all this makes sense :grimacing:

R

You are correct, except they won’t be namespaced.

<template>

    <h1>{{ title }}</h1>

    <p>{{ name }}</p>

    etc...

</template>
2 Likes

hmmmm…would the namespacing work, though? Maybe that’s nice for legibility and understandability in some situations?

Anyway, what if I had the same data name in two different modules being utilized in the same component, like so:

computed: {
  ...mapState('module/artists', ['name', 'age', 'location']);
  ...mapState('module/remixers', ['name', 'age', 'location'])
}

…then would this be the right thing to do?

<template>
    <h1>{{ artist.name }}</h1>
    <h1>{{ remixer.name }}</h1>
    etc...
</template>

…or is there another approach for this kind of situation?

Thanks! :grin:

R

You can provide an alias for names that would conflict, or simply for a name you want to be different inside the component.

1 Like

like this?

computed: {
  ...mapState('module/artists', ['name', 'age', 'location']);
  ...mapState('module/remixers', {
        name: 'remixerName',
        age: 'remixerAge',
        location: 'remixerLocation'
  })
}

Sorry y’all, but the docs for VueX are really tough for me as a beginner…it’s only after scouring the net and reading many different articles and watching many different videos that any of this is making any sense to me at all…basically I need a more thorough and clear explanation of the theory and I also need actual examples that illustrate said theory to really grasp these concepts…I’m finding VueX quite tough… :confused:

R

1 Like

mapState can take 2 types of values. An Array with direct name mapping, or an object, with key value pairs.

The key, being your alias name… and the value, being the state property, in your store ( or store module)

So lets look at one of the VueX examples.

export default {
  computed: mapState('moduleName', {
    // passing the string value 'count' is same as `state => state.count`
    countAlias: 'count',
  })
}

I’ve removed some extra stuff to show case their example.

As you can see, ‘count’ is the value defined in the store (state.count).
countAlias, is the name of the property you will use, to access it on your component. Hence the alias.

So in my component code I can do this

mymethod () {
   console.log(this.countAlias)
}

This object method, allows you to control situations where you may have conflicting property names. So lets use this example, with your variable names

  ...mapState('module/remixers', {
        remixerName: 'name',
        remixerAge: 'age'
        remixerLocation: 'location'
  })

Now in my component code, I can do the following.

mymethod () {
   console.log(this.remixerAge)
}
1 Like

soooooo…did I do the right thing then? I’z confused by the docs…

given this state:

state: {
user: 'Tom',
age: 25
}

mapState returns an object with functions returning the given state:

mapState(['user', 'age'])
// returns:
{
  user () {
    return this.$store.state.user
  },
  age () {
    return this.$store.state.age
  }
}

Now, using the Object rest spread operator, we can insert this result into our computed properties::slight_smile:

computed: {
  ...mapState(['user', 'age']), // no semicolon - we are "in" an object, you can only use a comma.
  myOwnComputedProp() {  return whatever }
}

results in:

computed: {
  user () {
    return this.$store.state.user
  },
  age () {
    return this.$store.state.age
  },
  myOwnComputedProp() {  return whatever }
}

(If the object rest spread operator confuses you, read up on it.)

Have you understood that part? Then we can talk about the other variations of this method, with namespaces etc.

4 Likes

got it on the semicolon, was missing that subtle detail :grimacing:

So…the spread operator takes the mapState concept and allows it to live inside of a computed property as well then? mapState on it’s own does not need the spread operator, but if it’s inside a computed property then mapState needs the spread operator to exist? I think that I am understanding this part now, yes, so the alias thing is still a little murky.

You explaining what mapState actually returns turned on a giant lightbulb for me, however, so thank you :grin:

" need it to exist" sounds a bit off. What the operator does is take every key and value from the object that mapState returns, and mix those into the object that you call it in.

You could get a similar result with Object.assign(), but it would look less fluent:

computed: Object.assign({
  myOwnComputedProp() {  return whatever }
}, mapState(['user', 'age']))
2 Likes

apologies, but i do not understand what you mean by ‘a lie’

I do believe he means value, likely autocorrect being cheeky :wink:

1 Like

Also, depending on your requirements you may want to consider using getters to set predefined state returns from your Vuex module. For example, if you have a module called news you could export a news getter that exports your entire state like so:

const getters = {
  news (state) {
    return state;
  }
};

export default {
  //...
  getters
};

Within your component you can access the whole state

computed: {
  ...mapGetters([
    'news'
  ])
},

Have a look at https://vuex.vuejs.org/en/getters.html

1 Like

Exactly - I corrected my post. Also added example code showing how the same result would be achieved with Object.assign.

1 Like

ok, so I’m just trying to use mapState in a component to access data from a module, and I get the following errors:

and I don’t know what I’m supposed to do differently in my VueX store or in the component to make it work properly.

Here is my VueX Store:

import Vue from 'vue'
import Vuex from 'vuex'

import { work } from './modules/work.js'
import { clients } from './modules/clients.js'
import { team } from './modules/team.js'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    work,
    clients,
    team
  }
})

…and here is the logic in my component:

import { mapState } from 'Vuex'
import gridContentGrid from '../global/grid-content-grid.vue'
import gridContentCard from '../global/grid-content-card.vue'

export default {
  name: 'team',
  components: {
    gridContentGrid,
    gridContentCard
  },
  computed: {
    ...mapState('module/team', ['id', 'name', 'position', 'picture', 'alt', 'info', 'bio'])
  }
}

The template is simply trying to access the state from the mapState computed property, like so:

<grid-content-grid>
      <grid-content-card slot="content"
        v-for="member in team"
        v-bind:key="id"
      >
        <h1 slot="name">{{ name }}</h1>
        <h2 slot="position">{{ position }}</h2>
        <img
          slot="team-pic"
          class="team-pic"
          v-bind:src="picture"
          v-bind:alt="alt"
        >
        <p slot="info">{{ info }}</p>
        <router-link
          slot="router-link"
          v-bind:to="{ name: 'member', params: { id: id } }"
          tag="button"
        >
          More Info...
        </router-link>
      </grid-content-card>
    </grid-content-grid>

…soooo, yeah, I thought team was defined as a module here, but it does not seem to work for me…

R

it should probably look like this:

mapState('team', ['id', 'name', 'position', 'picture', 'alt', 'info', 'bio'])

module/ is not some magic string to use with modules. you would only use it if you actually had a module called module.

Demo:

https://jsfiddle.net/n9jmu5v7/1625/

2 Likes

You’re fiddle does not seem to be working on my machine…dunno if it’s just me, tho.

Got it on ‘module’, did not know that the word ‘module’ itself was for illustrative purposes.

So, I’m down to one error in the console:

so then I thought I needed to add the ‘team’ key to the data function, like so:

data () {
    return {
        team: this.$store.state.team
    }
},

and low and behold, the error goes away…buuuuut…the v-for still doesn’t work in the template, and no content shows up or is iterated upon, there are just no errors in the console. So I’m thinking that I need to hook the mapState up to the data property of team in some way? Or that I’m just using the v-for loop incorrectly. The I looked in the Vue Dev Tools and it seems that my vex bindings are undefined to vue:

So I’m basically stuck trying to connect the mapState to the team key, maybe? Not sure if it should work this way…

Here is the v-for loop in the template, just in case you can see something that I’m doing wrong:

<grid-content-card
    slot="content"
    v-for="member in team"
    v-bind:key="id"
>

and thank you for your help and patience through all of my struggles. I really think it will sink in at some point. Most of the rest of Vue has been so logical and sensical. It’s really just VueX that I have struggled with :slight_smile: