vuex學習總結
什麽是Vuex?
官網定義:
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
這段話說明vuex有兩個特點:集中管理、狀態變化可以預測。 在介紹這兩個特點之前,先了解下什麽是狀態,以及為什麽要對狀態進行管理。
狀態是驅動應用的數據源。
通俗的講就是組件中綁定的數據。例如:導航控件綁定的菜單數據、控制導航展開或收攏的數據等等。
為什麽要狀態管理?
既然狀態是組件需要綁定的數據,那為什麽不直接寫在組件的data方法裏呢?當這個狀態只在一個組件中使用時,當然直接在data中定義就可以。但是當多個組件都依賴同一個狀態或者都會修改同一個狀態時,處理起來就比較麻煩。
因為在vue中,組件通過prop註冊自定義屬性。父組件通過給子組件的自定義屬性賦值將數據傳給子組件。另外子組件不能直接修改父組件的數據,它可以emit一個事件,將變更後的數據通過事件參數傳給父組件,父組件捕獲到事件後更新數據。 這樣的話對下面這些場景處理起來就很麻煩:
- 兩個兄弟關系(或者毫無關系)的組件都依賴於同一個狀態,A組件修改狀態後,B組件也要更新;此時A組件無法把修改後的狀態傳給B。
- 祖先向後代組件傳遞數據; 需要通過prop一層層的的傳遞,非常繁瑣。
vuex
集中管理:vuex把組件的共享狀態抽取出來,以一個全局單例模式進行管理,在這種模式下,我們的組件樹構成了一個巨大的“視圖”,不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為。
狀態變化可以預測:不允許組件直接修改狀態,而是在vuex內部,通過mutation來修改狀態,這樣每次狀態的變更都可以追蹤;
Vuex的核心概念
每一個 Vuex 應用的核心就是 store(倉庫),store集中管理所有的狀態。它和單純的全局對象比有兩點不同:
- vuex中的狀態是響應式的,若 store 中的狀態發生變化,那麽相應的組件也會相應地得到高效更新;
- 組件不允許直接修改屬於store的狀態,而應執行 action 來分發 (dispatch) 事件通知 store 去改變,這樣使得我們可以方便地跟蹤每一個狀態的變化;
創建store對象的時候需要傳遞構造器選項,具體如下所示。構造器選項有:state, mutations, actions, getters, modules等,下面是這些選項的用法。
const store = new Vuex.Store({
state: {
products: [{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},]
},
getters: {
productsCount: state => {
return state.products.length;
}
},
mutations: {
increment (state) {
state.count++
}
}
})
- State
如何在組件中展示狀態? 通過在vue根實例中註冊store選項,store會註入到所有子組件中,這樣子組件能通過this.$store訪問到。
如果組件要顯示一個狀態,通常會先定義一個計算屬性,然後在計算屬性返回store中的狀態,組件綁定該計算屬性。
<template>
<div>
{{productsCount}}
</div>
</template>
<script>
export default {
computed: {
productsCount() {
return this.$store.state.productsCount;
}
}
}
</script>
mapState輔助函數
當一個組件需要獲取多個狀態時,將這些狀態都聲明為計算屬性會有些重復和冗余,mapState函數可以幫助我們少輸入些代碼。
例如: store中有兩個狀態, name, phone
new Vuex.Store({
state: {
name: ‘張紹‘,
phone: ‘13800138000‘
},
...
})
組件中通過mapState獲取這兩個狀態( ...是ES6中的擴展運算符, 具體用法可參考《ES6 ... 擴展運算符》)
<template>
<div>
{{name}} / {{phone}}
</div>
</template>
<script>
import { mapState } from ‘vuex‘
export default {
computed: {
...mapState([
‘phone‘,
‘name‘,
]),
}
}
- Getter
有時候我們組件需要顯示加工處理後的狀態數據,例如store中有一個待辦任務列表的狀態數據,但是組件需要顯示已完成的待辦任務,如果每個組件都在自己的計算屬性進行過濾會重復操作,增加代碼量。這個時候可以在store中定義一個getter, 在這個getter中進行計算過濾,然後組件的計算屬性中直接返回這個getter。
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)
}
}
})
組件
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
- Mutation
不允許組件直接修改狀態,更改狀態的唯一方法是提交mutation,然後在mutation中修改;
在vuex.store的mutations選項中定義一個mutation, mutation回調函數接收一個參數state,通過state取到狀態數據。
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態
state.count++
}
}
})
組件中提交mutation更改狀態
<template>
<el-button @click="incrementCount">修改狀態</el-button>
</template>
<script>
export default {
methods: {
incrementCount() {
this.$store.commit(‘increment‘);
}
}
}
</script>
- Action
mutation中的操作是同步的,如果我們需要在異步執行某些操作後修改狀態,則只能使用action。 Action可以包含異步操作,在Action中提交mutation來修改狀態。
定義一個Action
const store = new Vuex.Store({
...
actions: {
increment (context) {
setTimeout(() => {
context.commit(‘increment‘)
}, 1000)
}
}
})
組件中分發Action
this.$store.dispatch(‘increment‘)
- Module
對於一個大型的應用,所有的狀態都集中在一個對象中,會變得非常臃腫。vuex允許我們將store分割成模塊,每個模塊擁有自己的state, mutation, action, getter,甚至是嵌套子模塊。類似下面代碼:
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 的狀態
store.state.b // -> moduleB 的狀態
Vuex的安裝使用
- 首先安裝vuex
npm install vuex --save
- 顯式地通過Vue.use(),引入vuex
import Vuex from ‘vuex‘
Vue.use(Vuex)
- 實例化Vuex.Store對象
const store = new Vuex.Store({
state: {
...
},
getters: {
...
},
mutations: {
...
}
actions: {
...
}
})
- 將store註入到Vue實例中,這樣該 store 實例會註入到根組件下的所有子組件中,且子組件能通過 this.$store 訪問到
new Vue({
el: ‘#app‘,
router,
store,
template: ‘<App/>‘,
components: { App },
});
註意事項:對於大型的應用,通常會把vuex相關代碼分割到模塊中,大概的項目結構如下:(官網有個購物車的例子可以參考)
參考資料
- Vuex官方文檔
- Vue組件
- ES6 ... 擴展運算符
後記
此文是對官網資料的學習總結,其中夾雜了些自己對vuex的理解,如果有理解有誤的地方,歡迎大家指出。
vuex學習總結