vuex 理解
vuex 是什麼
1) github 站點: https://github.com/vuejs/vuex
2) 在線文檔: https://vuex.vuejs.org/zh-cn/
3) 簡單來說: 對 vue 應用中多個組件的共享狀態進行集中式的管理(讀/寫)
狀態自管理應用
1) state: 驅動應用的數據源
2) view: 以聲明方式將 state 映射到視圖
3) actions: 響應在 view 上的用戶輸入導致的狀態變化(包含 n 個更新狀態的方法)
多組件共享狀態的問題
1) 多個視圖依賴於同一狀態
2) 來自不同視圖的行爲需要變更同一狀態
3) 以前的解決辦法
a. 將數據以及操作數據的行爲都定義在父組件
b. 將數據以及操作數據的行爲傳遞給需要的各個子組件(有可能需要多級傳遞)
4) vuex 就是用來解決這個問題的
vuex 核心概念和 API
state
1) vuex 管理的狀態對象
2) 它應該是唯一的
const state = {
xxx: initValue
}
mutations
1) 包含多個直接更新 state 的方法(回調函數)的對象
2) 誰來觸發: action 中的 commit('mutation 名稱')
3) 只能包含同步的代碼, 不能寫異步代碼
const mutations = {
yyy (state, {data1})
{
// 更新 state 的某個屬性
}
}
actions
1) 包含多個事件回調函數的對象
2) 通過執行: commit()來觸發 mutation 的調用, 間接更新 state
3) 誰來觸發: 組件中: $store.dispatch('action 名稱', data1) // 'zzz'
4) 可以包含異步代碼(定時器, ajax)
const actions = {
zzz ({commit, state}, data1){
commit(
'yyy', {data1}
)
}
}
getters
1) 包含多個計算屬性(get)的對象
2) 誰來讀取: 組件中: $store.getters.xxx
const getters = {
mmm (state) {
return ...
}
}
modules
1) 包含多個 module
2) 一個 module 是一個 store 的配置對象
3) 與一個組件(包含有共享數據)對應
向外暴露 store 對象
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
組件中
import {mapState, mapGetters, mapActions} from 'vuex'
export default {
computed: {
...mapState(['xxx']),
...mapGetters(['mmm']),
}
methods: mapActions(['zzz'])
}
{{xxx}} {{mmm}} @click="zzz(data)"
映射 store
import store from './store'
new Vue({
store
})
store 對象
1) 所有用 vuex 管理的組件中都多了一個屬性$store, 它就是一個 store 對象
2) 屬性: state: 註冊的 state 對象 getters: 註冊的 getters 對象
3) 方法: dispatch(actionName, data): 分發調用 action
實際案例
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
/*state 對象 類似於 data */
const state = {
count: 0
// 初始化狀態數據
}
/*
mutations 對象包含個方法:
能直接更新 state 一個方法就是一個 mutation mutation
只能包含更新 state 的同步代碼, 也不會有邏輯
mutation 由 action 觸發調用: commit('mutationName')
*/
const mutations = {
INCREMENT(state) {
state.count++
},
DECREMENT(state) {
// ctrl + shift + x
state.count--
}
}
/*
actions 對象 包含個方法: 觸發 mutation 調用,
間接更新 state 一個方法就是一個 action action
中可以有邏輯代碼和異步代碼 action 由組件來觸發調用:
this.$store.dispatch('actionName')
*/
const actions = {
increment({
commit
}) {
commit('INCREMENT')
},
decrement({
commit
}) {
commit('DECREMENT')
},
incrementIfOdd({
commit,
state
}) {
if (state.count % 2 === 1) {
commit('INCREMENT')
}
},
incrementAsync({
commit
}) {
setTimeout(() => {
commit('INCREMENT')
}, 1000)
}
}
/*getters 對象 包含多個 get 計算計算屬性方法 */
const getters = {
oddOrEven(state) {
return state.count % 2 === 0 ? '偶數' : '奇數'
},
count(state) {
return state.count
}
}
// 向外暴露 store 實例對象
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
main.js
import Vue from 'vue'
import app from './app.vue'
import store from './store'
// 創建 vue 配置路由器
new Vue({
el: '#app',
store,
render: h => h(app)
})
app.vue(未優化前)
<template>
<div>
<p>clicked: {{$store.state.count}} times, count is {{oddOrEven}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
</template> <script>
export default {
computed: {
oddOrEven() {
return this.$store.getters.oddOrEven;
}
},
methods: {
increment() {
this.$store.dispatch("increment");
},
decrement() {
this.$store.dispatch("decrement");
},
incrementIfOdd() {
this.$store.dispatch("incrementIfOdd");
},
incrementAsync() {
this.$store.dispatch("incrementAsync");
}
}
};
</script> <style>
</style>
app2.vue(優化後)
<template>
<div>
<p>clicked: {{count}} times, count is {{oddOrEven2}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
</template> <script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: mapGetters({
// 名稱不一樣
oddOrEven2: "oddOrEven",
count: "count"
}),
methods: mapActions([
"increment",
"decrement",
"incrementIfOdd",
"incrementAsync"
]) // 名稱一樣
};
</script>
<style>
</style>