Vue.js - Study Note 6
Vuex
Vuex defines itself as such:
"Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion."
Install
npm install vuex --save
or using the CDN links
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
The core part of the Vuex store is in store.js . It is as follow:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
//......
},
mutations: {
//......
},
getters: {
//......
},
actions: {
//......
}
})
export default store;
Flux (State Management Pattern)
Flux is a scalable data handling pattern (not a library) developed by Facebook, and the concept rapidly found adoption in front-end frameworks. One of the well known problems was Facebook’s notification bug. When a user logged in to Facebook, he/she sees a notification on the message icon. However, when that user clicked on it, there would be no message and the notification disappeared. After a while, it would came back and again with the same same story — the user clicked on the message icon, but no new message.
The Facebook developer team fixed the bug several times which worked fine for a while, but eventually it would reappear. Finally, they decided to solve the problem and fix the bug once and developed a data management pattern, Flux.
Flux has 4 main components (Action, Dispatcher, Store, View) and 2 principles (Single Source of Truth, Read-Only Data).
-
Single Source of Truth Basically, every Vue application should have 2 types of data: Local and Global data. Local data: Each component has its own local data that is accessible within that component and can be passed to other components through emitting events and props. Global data: Application’s global data should be accessible through all components and should be kept in a single place, separated from components. This single place is the store and this conception is called SSOT (Single Source of Truth).
-
Read Only Data Each component is capable of reading global application data from the store, but they are not able to change it. If any component intends to change data in store, they should do it through
mutations
andactions
. This is because we do not want any component to intentionally or unintentionally change our global state.
State
State
, vuex uses a single state tree when one object contains the entire global state of the application and serves as the only one source. It also means that the app will have only one such storage. A single state tree makes it easy to find the part you need or take snapshots of the current state of the application for debugging purposes.
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
Whenever store.state.count changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates. 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
}
})
}
Getters
Getters
, vuex allows us to define "getters" in the store. You can think of them as computed properties for stores. Like computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
// ...
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
store.getters.doneTodes
Mutations
Mutations
, the only way to actually change state in a Vuex store is by committing a mutation with commit()
. Vuex mutations are very similar to events: each mutation has a string type and a handler. The handler function is where we perform actual state modifications, and it will receive the state as the first argument. You cannot directly call a mutation handler.
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
plus(state){
state.count++
},
less(state){
state.count--
}
}
});
Paylaod of mutation
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
plus(state,n){
state.count+=n
},
less(state,n){
state.count-=n
}
}
});
this.$store.commit('plus',5)
this.$store.commit('less',5)
Actions
Actions
, actions are similar to mutations with a few differences, instead of mutating the state, actions commit mutations; actions can contain arbitrary asynchronous operations.
actions:{
plus(commit){
commit({type:'plus',n:5})
}
}