從零開始的vue學習筆記(七)
- 2019 年 10 月 15 日
- 筆記
前言
今天花一天時間閱讀完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
來出發actionsstore.dispatch('increment')
更多語法細節見鏈接
-
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
確保每個模塊的獨立命名空間,更多語法細節見鏈接 - 其他
其他的主題包括:- 項目結構
- 插件
- 嚴格模式
- 表單處理
- 測試
- 熱重載
這些主題不是核心問題,在需要看的時候或者自己感興趣的再來看,詳見鏈接。