State

In Vue, states are just data that we have been using. These are actually property.

Single State Tree

Vuex uses a single state tree - that is, this single object contains all your application level state and serves as the "single source of truth". This also means usually you will have only one store for each application. A single state tree makes it straightforward to locate a specific piece of state, and allows us to easily take snapshots of the current app state for debugging purposes.

The single state tree does not conflict with modularity - in later chapters we will discuss how to split your state and mutations into sub modules.

Inject Store

Notice in our previous lesson how we have accessed the state in our components. It looks like the following example -

// let's create a Counter component
const Counter = {
	template: `<div>{{ count }}</div>`,
	computed: {
		count () {
			return store.state.count
		}
	}
}

This way the component is relying on the global object store as the single source of truth. When you are using a module system, the store won't be available as global object. So accessing store this way would be wrong. In module system, you need to import the store in every component that uses store data and also requires mocking when testing the component. Importing store in every components gets really verbose when components grows in numbers.

To overcome this problem, Vuex provides a mechanism to "inject" the store into all child components from the root component with the store option (enabled by Vue.use(Vuex)):

const app = new Vue({
  el: '#app',
  // provide the store using the "store" option.
  // this will inject the store instance to all child components.
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

This way you inject the store only in one component, which is the root component of your application. Vue will automatically inject the store in every child component. This way you need to import your store only at one place, where you define your root component. You now don't need to import store in any other component. Now you can use this.$store to access states or mutations.

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

mapState Helper

When a component needs to make use of multiple store state properties or getters, declaring all these computed properties can get repetitive and verbose. To deal with this we can make use of the mapState helper which generates computed getter functions for us, saving us some keystrokes:

// in full builds helpers are exposed as Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // arrow functions can make the code very succinct!
    count: state => state.count,

    // passing the string value 'count' is same as `state => state.count`
    countAlias: 'count',

    // to access local state with `this`, a normal function must be used
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

Let's explain the above example in details -

In the above example, the mapState helper assumes that you have one single source of truth, and it is called store. In the example, mapState Helper takes an object, within it we have defined three computed properties. count, countAlias and countPlusLocalState.

In the first computed property count, we have used arrow function syntax. In your component you can access the computed property using this.count.

In the second computed property countAlias, we have even shorter syntax, you just pass the the name of the state as string. The Vuex will automatically map the string "count" to "store.state.count". Now you can access this computed property using this.countAlias in your component.

In the third computed property countPlusLocalState, we have used function syntax. It is necessary to use function syntax when you have a computed property whose dependecies are local state and store state. So if you are using local component state with the mix of store state, you need to use function syntax. This function must accept state as the first argument which is equivalent to store.state.

We can also pass a string array to mapState when the name of a mapped computed property is the same as a state sub tree name.

computed: mapState([
  // map this.count to store.state.count
  'count'
])

Object Spread Operator

Note that mapState returns an object. Which contains all the mapped computed properties. These computed properties have state as their dependecies. But how do we define our local computed properties that depends on only local state? Normally, we'd have to use a utility to merge multiple objects into one so that we can pass the final object to computed. However with the object spread operator (which is a stage-4 ECMAScript proposal), we can greatly simplify the syntax:

computed: {
  localComputed () { /* ... */ },
  // mix this into the outer object with the object spread operator
  ...mapState({
    // ...
  })
}