1. 程式人生 > >20181128——Vuex學習

20181128——Vuex學習

閱讀Vuex官方文件,Vuex官方文件



**Vuex是什麼** Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也整合到 Vue 的官方除錯工具 devtools extension,提供了諸如零配置的 time-travel 除錯、狀態快照匯入匯出等高階除錯功能。

什麼是“狀態管理模式”?

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

這個狀態自管理應用包含以下幾個部分:

state,驅動應用的資料來源;
view,以宣告方式將 state 對映到檢視;
actions,響應在 view 上的使用者輸入導致的狀態變化。
以下是一個表示“單向資料流”理念的極簡示意:
在這裡插入圖片描述
但是,當我們的應用遇到多個元件共享狀態時,單向資料流的簡潔性很容易被破壞:

多個檢視依賴於同一狀態。
來自不同檢視的行為需要變更同一狀態。
對於問題一,傳參的方法對於多層巢狀的元件將會非常繁瑣,並且對於兄弟元件間的狀態傳遞無能為力。對於問題二,我們經常會採用父子元件直接引用或者通過事件來變更和同步狀態的多份拷貝。以上的這些模式非常脆弱,通常會導致無法維護的程式碼。

因此,我們為什麼不把元件的共享狀態抽取出來,以一個全域性單例模式管理呢?在這種模式下,我們的元件樹構成了一個巨大的“檢視”,不管在樹的哪個位置,任何元件都能獲取狀態或者觸發行為!

另外,通過定義和隔離狀態管理中的各種概念並強制遵守一定的規則,我們的程式碼將會變得更結構化且易維護。

這就是 Vuex 背後的基本思想,借鑑了 Flux、Redux、和 The Elm Architecture。與其他模式不同的是,Vuex 是專門為 Vue.js 設計的狀態管理庫,以利用 Vue.js 的細粒度資料響應機制來進行高效的狀態更新。

什麼情況下我應該使用 Vuex?
雖然 Vuex 可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。

如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。引用 Redux 的作者 Dan Abramov 的話說就是:

Flux 架構就像眼鏡:您自會知道什麼時候需要它。

開始
每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含著你的應用中大部分的狀態 (state)。Vuex 和單純的全域性物件有以下兩點不同:
Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。

最簡單的 Store

// 如果在模組化構建系統中,請確保在開頭呼叫了 Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

現在,你可以通過 store.state 來獲取狀態物件,以及通過 store.commit 方法觸發狀態變更:

 store.commit('increment')

console.log(store.state.count) // -> 1

再次強調,我們通過提交 mutation 的方式,而非直接改變 store.state.count,是因為我們想要更明確地追蹤到狀態的變化。這個簡單的約定能夠讓你的意圖更加明顯,這樣你在閱讀程式碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓我們有機會去實現一些能記錄每次狀態改變,儲存狀態快照的除錯工具。有了它,我們甚至可以實現如時間穿梭般的除錯體驗。

由於 store 中的狀態是響應式的,在元件中呼叫 store 中的狀態簡單到僅需要在計算屬性中返回即可。觸發變化也僅僅是在元件的 methods 中提交 mutation。

<div id="app">
  <p>{{ count }}</p>//此處的count就是Vue例項中的count計算屬性	
  <p>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </p>
</div>
// make sure to call Vue.use(Vuex) if using a module system

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
  	increment: state => state.count++,
    decrement: state => state.count--
  }
})

new Vue({
  el: '#app',
  computed: {
    count () {
	    return store.state.count
    }
  },
  methods: {
    increment () {
      store.commit('increment') //監聽的v-on事件,進行觸發, 然後穿到mutation中
    },
    decrement () {
    	store.commit('decrement')
    }
  }
})

State
單一狀態樹
Vuex 使用單一狀態樹——是的,用一個物件就包含了全部的應用層級狀態。至此它便作為一個“唯一資料來源 (SSOT)”而存在。這也意味著,每個應用將僅僅包含一個 store 例項。單一狀態樹讓我們能夠直接地定位任一特定的狀態片段,在除錯的過程中也能輕易地取得整個當前應用狀態的快照。

單狀態樹和模組化並不衝突——在後面的章節裡我們會討論如何將狀態和狀態變更事件分佈到各個子模組中。
在 Vue 元件中獲得 Vuex 狀態
那麼我們如何在 Vue 元件中展示狀態呢?由於 Vuex 的狀態儲存是響應式的,從 store 例項中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:

// 建立一個 Counter 元件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}

每當 store.state.count 變化的時候, 都會重新求取計算屬性,並且觸發更新相關聯的 DOM。

然而,這種模式導致元件依賴全域性狀態單例。在模組化的構建系統中,在每個需要使用 state 的元件中需要頻繁地匯入,並且在測試元件時需要模擬狀態。

Vuex 通過 store 選項,提供了一種機制將狀態從根元件“注入”到每一個子元件中(需呼叫 Vue.use(Vuex)):

const app = new Vue({
  el: '#app',
  // 把 store 物件提供給 “store” 選項,這可以把 store 的例項注入所有的子元件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

mapState 輔助函式
當一個元件需要獲取多個狀態時候,將這些狀態都宣告為計算屬性會有些重複和冗餘。為了解決這個問題,我們可以使用 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
}

})
}



大白話講解Vuex 官方是這麼說的:Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

不懂?呵呵,沒關係。我是這麼認為的:Vuex 就是前端為了方便資料的操作而建立的一個” 前端資料庫“。且聽下文分解。。。

模組間是不共享作用域的,那麼B 模組想要拿到 A 模組的資料,我們會怎麼做?不要去想什麼”狀態管理“、”vuex“、”redux“、”函數語言程式設計“什麼的。。。

我們會定義一個全域性變數,叫 aaa 吧,就是 window.aaa。然後把A 模組要共享的資料作為屬性掛到 B 模組上。這樣我們在 B 模組中通過 window.aaa 就可以拿到這個資料了。

但是問題來了,B 模組拿到了共享的資料,就叫他 xxx 吧?得了,名字太混亂了,咱先給它們都改下名字。那個全域性變數既然是存東西的,就叫 store 吧,共享的資料就叫 state 吧,你叫他 data 也一樣,反正我是叫它 state 了。

繼續說我們的問題,問題是什麼呢?B 模組拿到了 A 模組的資料 state,但是這個資料不是一成不變的呀,A 要操作這個資料的。那麼我們是不是要在這個資料——state 改變的時候通知一下 B?那寫個自定義事件吧。。。

好吧,你自己已經實現了一個迷你版的 vuex,其實 vuex 就幫你做了這點事兒。我們來看下它裡面都有什麼玩意兒。

這就是一個典型的 使用vuex生成的倉庫。不懂?呵呵,沒關係,也沒打算說它。我們聊點別的。

後端是幹什麼的?進行資料庫操作,處理請求,根據請求分發響應。我們就聊聊資料庫的操作,不說 API。首先,你得能取吧?那麼得有一套取資料的 API,我們給他們集中起個名字吧?既然是獲取,那就叫getter 吧。我們還得存資料呀,是吧。存資料就是對資料庫的修改,這些 API,我們也得給它起個名字,就叫 mutation,就這麼定了。

OK,vuex 生成的倉庫也就這麼出來了,所以我說 vuex 就是” 前端的資料庫“。State 就是資料庫。Mutations 就是我們把資料存入資料庫的 API,用來修改 state 的。getters 是我們從資料庫裡取資料的 API,既然是取,那麼你肯定不能把資料庫給改了吧?所以 getters 得是一個”純函式“,就是不會對原資料造成影響的函式,比如 陣列的concat()方法、slice()方法;與之對應的是陣列的 push()方法、splice()方法,他們會改變原陣列的值。然後我們把這幾部分用 store 包一下,” vuex “就搗置出來了,用資料了就從 state 中取,改資料了記得 mutation 到 state 中。

哎,還漏了個 actions 呢。你想呀,後端從前端拿到了資料,總要做個處理吧,處理完了再存到資料庫中。其實這就是 action的過程。當然你也可以不做處理,直接丟到資料庫,所以vuex也可以在 action 中直接存,就是直接mutation。

現在,我們再來看看 vuex 的資料流。後(qian)端通過 action處理資料,然後通過 mutation 把處理後的資料放入資料庫(state)中,誰要用就通過 getter從資料庫(state)中取。

你都理解了?好吧,有卵用,還得迴歸到 API 上。

Vuex 什麼時候用?
果你問了這個問題,說明你不該用。但這個問題可以很容易並且很正確的回答。

等你痛了的時候,你就該用了。如果你連自己的程式碼都看不懂的時候,如果你自己都搞不清楚值在元件中是怎麼傳遞的時候,如果你自己程式碼寫了一半,噁心的想要撂挑子不幹的時候,趕緊的,Vue.use(Vuex)!

Vuex+Vue