Vuex
Basic Concepts
Store is the center of vuex. Store is where vuex saves all data together. Store will hold the application State.
When Vue components retrieve state from it, they will reactively and efficiently update if the store’s state changes.
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
You cannot directly mutate the store’s state. The only way to change a store’s state is by explicitly committing mutations.
If we want to execute the increment function,
store.commit('increment')
Vuex uses a single state tree which 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
For the best practice, we can create a store folder.
store
|_index.js
|_action.js
|_mutation.js
|_getter.js
|_mutation_types.js
Within the store/index.js, we set:
Vue.use(Vuex)
Then use it in main.js
new Vue({
router,
store,
}).$mount('#app')
By providing the store option to the root instance, the store will be injected into all child components of the root and will be available on them as this.$store
For Example:
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState
mapState is a helper for vuex. When using the state within the component, it will be insufficient to declare getter function one by one. We can use mapState to simply map one this attribute to state.
e.g.
// 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
}
})
}
Object Spread Operator
it’s kind of advanced function for mapState e.g.
computed: {
localComputed () { /* ... */ },
// mix this into the outer object with the object spread operator
...mapState({
// ...
})
}
getters
getters is a list of function defined in Store which can be reused in multiple component.
mapGetters
mapGetters is similar to mapState. It reduce the complexity of importing getters function.
Commit with Payload
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
Using Constants for Mutation Types
The best practice is to define mutation types within the project.
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
Mutations Must Be Synchronous
But we can use async/await within the mutation functions
mapMutations
mapMutations is a better way to import mutation functions
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // map this.increment() to this.$store.commit('increment')
// mapMutations also supports payloads:
'incrementBy' // this.incrementBy(amount) maps to this.$store.commit('incrementBy', amount)
]),
...mapMutations({
add: 'increment' // map this.add() to this.$store.commit('increment')
})
}
}
Modules
Due to using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated.
To help with that, Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules – it’s fractal all the way down:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA's state
store.state.b // -> moduleB's state
Action
Asynchronous logic should be encapsulated in, and can be composed with actions.
├── index.html
├── main.js
├── api
│ └── ... # abstractions for making API requests
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # where we assemble modules and export the store
├── actions.js # root actions
├── mutations.js # root mutations
└── modules
├── cart.js # cart module
└── products.js # products module
CSS Grid
CSS grid is a layput solution.