從零開始的vue學習筆記(七)
前言
今天花一天時間閱讀完vuex的官方文件,簡單的做一下總結和記錄
Vuex是什麼
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,以前的符合“單向資料流”理念的示意圖:
它包含三個部分:
- state,驅動應用的資料來源;
- view,以宣告方式將 state 對映到檢視;
- actions,響應在 view 上的使用者輸入導致的狀態變化。
當我們的應用遇到多個元件共享狀態時,單向資料流的簡潔性很容易被破壞:
- 多個檢視依賴於同一狀態。
- 來自不同檢視的行為需要變更同一狀態。
實際上就是一個元件間通訊的問題,原來是用$ref直接引用子元件,或者多層巢狀元件,或者依賴注入provide
inject
等暴力方式,在應用和元件複雜的情況下複雜度和可維護性都會成為巨大問題。
所以,vuex就誕生了,vuex的原理圖:
這個圖描述了vuex的資料傳導邏輯,綠色虛線部分為vuex外掛本身
- 首先,
Vuex
自身提供了一個store
(倉庫),資料結構為樹形的,採用單例設計,裡面用key-value
(value可以是string、數字、陣列、Object等)的形式包含了一個應用的各種狀態值,並提供了響應式的狀態更新,提供給vue元件Render
來渲染。 - 傳統的Vue元件接受使用者對介面的操作後,通過分發(
Dispatch
)這些前端事件或者說響應給Vuex的Action
,在Action
非同步
呼叫一些其他的後端API Action
通過Commit
來提交對應的Mutations
裡的方法,達到呼叫Mutations
裡的方法的目的,這個時候可以用Devtools
外掛來追蹤狀態資料在Mutations
裡的方法呼叫前後的資料變化,形成快照等(Mutations
裡的方法必須是同步
的)Mutations
裡的一些mutation
(變異)方法體執行,改變應用的一些State狀態屬性,這些mutation
是Vuex改變狀態的唯一途徑,直接修改State狀態值是不允許的(資料不可追蹤),從而形成了單向資料流
的完整鏈路,同時狀態是可維護
、可追蹤
、響應式
、可複用
下面就一起來看看Vuex的各個詳細部分:
安裝
直接下載(推薦)或者CDN引入
從https://unpkg.com/vuex下載下來,然後通過js引入:<script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script>
npm/yarn
//npm npm install vuex --save //yarn yarn add vuex
模組化的打包系統
import Vue from 'vue' import Vuex from 'vuex' //前面vue基礎部分就有Vue.use()引入外掛的用法, //下面這句在打包系統中是必備的 Vue.use(Vuex)
核心概念
State
首先,Vuex的所有概念都只有一個api:圍繞Vuex.Store(...options) 這個構造器展開,類似Vue的概念都圍繞Vue的構造器展開一樣;State的作用就類似於Vue裡面的data
,簡單的new Vuex的例子:// 如果在模組化構建系統中,請確保在開頭呼叫了 Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
這樣,在我們的Vue外掛裡就可以用computed計算屬性來獲取這些state值:
// 建立一個 Counter 元件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } }
為了簡化寫法(少些程式碼),官方提供了一個
mapState
輔助函式避免寫store.state.count
這一長串,其他的輔助函式mapGetters
、mapActions
、mapMutations
都是類似的作用,API連結
例子:
// 在單獨構建的版本中輔助函式為 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭頭函式可使程式碼更簡練
count: state => state.count,
// 傳字串引數 'count' 等同於 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取區域性狀態,必須使用常規函式
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
Getter
單純的用State裡的狀態值還不夠強大,所以Vuex提供了Getter來對State作進一步的複雜邏輯處理,類似於Vue裡面的computed計算屬性對data的進一步處理一樣。
例子: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) } } })
如果對更多的語法細節感興趣,可以閱讀官方連結
Mutation
Mutaion中文解釋是變異,用來執行對State狀態改變的同步
方法,可以簡單的類比Vue中的methods,只不過Vue中的methods沒有區分同步
和非同步
方法,而Vuex中為了追蹤資料狀態,用Mutation執行同步方法,Action直觀性非同步方法,做了這種拆分,讓Devtools等工具發揮作用。
例子:const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變更狀態 state.count++ } } })
更多的語法細節參考連結
- Action
Action 類似於 mutation,不同在於:- Action 通過commit提交的是 mutation,而不是直接變更狀態。
- Action 可以包含任意非同步操作
例子:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
元件裡通過
store.dispatch
來出發actions
更多語法細節見連結store.dispatch('increment')
- Action 通過commit提交的是 mutation,而不是直接變更狀態。
Module
如果只靠一個大的store裡的state狀態樹來維護整個應用,當規模巨大,勢必會有問題,所以引入Module做模組化的拆分,拆成按照名稱空間的子狀態樹。每個模組擁有自己的 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 的狀態
引入
namespaced: true
確保每個模組的獨立名稱空間,更多語法細節見連結- 其他
其他的主題包括:- 專案結構
- 外掛
- 嚴格模式
- 表單處理
- 測試
- 熱過載
這些主題不是核心問題,在需要看的時候或者自己感興趣的再來看,詳見連結