Vuex是vue的狀態管理器,它採用 集中式的存儲管理方式管理組件的全部狀態。並以必定的規則來保證狀態以一種 可預測的方向發生變化~~Vuex產生的原因html
new Vue({ // state data () { return { count: 0 } }, // view template: ` <div>{{ count }}</div> `, // actions methods: { increment () { this.count++ } } })
上面這個簡單的實例:包含了state、view視圖、actions操做。vue
三者以一種單向數據流的形式在運行着。可是若是咱們碰到了多組件須要共享狀態的時候,單向數據流就不大行了~~面試
遇到了種種問題,咱們會有疑問,爲何不使用一種全局單例模式對咱們的狀態進行一個全局的統一管理呢,這樣咱們的組件樹就成爲了一個大的視圖,無論咱們在樹的任何位置,咱們均可以對狀態進行獲取和action操做。這樣將使得咱們的項目可以更好的維護於發展。ajax
這是vuex的內部核心思想,它還借鑑了redux、flux等。vue高度契合vue的細粒度的數據響應機制,來實現高效的狀態管理。vuex
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export default new Vuex.Store({ state: { count: 1 // 計數 }, getters: { getCount(state) { return state.count > 120 ? 120 : state.count; } }, mutations: { add(state, num) { return state.count = state.count + num; }, de(state, payload) { state.count-=payload.n; } }, actions: { add(context) { setTimeout( ()=>{ context.commit('add', 100 ) }, 1000) } } });
<template> <div id="app"> <span>{{$store.state.count}}</span> <button @click="add">添加</button> <button @click="de">減小</button> </div> </template> <script> export default { name: "APP", methods: { add() { // this.$store.commit("add", 10) this.$store.dispatch('add'); }, de() { this.$store.commit("de", { n: 4 }) } } }; </script>
上面實現了一個簡單的例子;redux
答:有五種,分別是 State
、 Getter
、Mutation
、Action
、 Module
;promise
state是整個Vuex的核心,這裏咱們使用的是一個單一狀態樹,也就是惟一數據源,這裏跟module並不衝突。一個組件樹共享一個store。緩存
vuex的狀態是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態app
computed: { count() { return this.$store.state.count } },
計算屬性是依賴響應,基於依賴進行計算,當它的依賴發生了變化的時候,纔會從新計算咱們的返回值。異步
由於咱們的Vuex會被全部組件去使用,若是咱們頻繁的導入顯得不是很合理,Vue爲咱們提供了機制能夠從根組件注入到每個自組件中。
new Vue({ router, store, render: h => h(App) }).$mount("#app");
同時vuex爲咱們提供了語法糖,方便咱們去批量獲取狀態。
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 } }) }
咱們還能夠更簡潔,可是要求咱們的屬性和store中的一致
computed: mapState([ // 映射 this.count 爲 store.state.count 'count' ])
可是若是咱們還有其餘的計算屬性呢,咱們可使用...擴展運算符混入。
computed: { localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }
state:惟一性、響應式、獲取用計算屬性computed。 語法糖:mapState。
getter跟計算屬性有點相似,它主要解決什麼問題呢?
當咱們想要對某一個狀態列表篩選的時候,咱們能夠在computed中進行篩選,可是若是咱們多個組件都使用呢,咱們是否是得每一個組件都複製一份呢,顯然不合理了,所以vuex容許咱們在vuex內去抽離一個篩選或者處理的公共方法。這樣咱們就沒必要要每次都重寫一遍了。
getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } getters: { getCount(state) { return state.count > 120 ? 120 : state.count; } },
Getter 也能夠接受其餘 getter 做爲第二個參數:
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
使用:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
一樣vuex也提供了語法糖:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
同時咱們還能夠給getter去傳遞參數
getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } }
注意,getter 在經過方法訪問時,每次都會去進行調用,而不會緩存結果。
本人理解getter就是對狀態的一個預約義處理和篩選,複用性,可預測性好。
vuex規定了咱們狀態的惟一改變方式就是經過提交mutation來更改。每個mutation都有一個type類型表示咱們操做的類型,還有一個handler用來標明咱們的具體操做過程。
最簡單的形式就是:
mutations: { add(state, num) { return state.count = state.count + num; }, de(state, payload) { state.count-=payload.n; } }, // 調用執行 this.$store.commit("add", 10) this.$store.commit("de", { n: 4 })
咱們還可使用對象風格的方式提交:
this.$store.commit({ type: 'add', n: 4 }) // 這種風格會把整個對象做爲載荷傳遞過去。
注意點:
當須要在對象上添加新屬性時,你應該 一、使用 Vue.set(obj, 'newProp', 123), 或者 二、以新對象替換老對象。state.obj = { ...state.obj, newProp: 123 }
可是一般咱們會使用一個字符串常量來代替咱們的mutation事件類型。
const store = new Vuex.Store({ state: { ... }, mutations: { // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名 [SOME_MUTATION] (state) { // mutate state } } })
還須要注意的是,mutation的操做必須是同步的,異步執行會單獨放在action中執行。緣由實際上是異步操做咱們不知道如何執行完,若是咱們執行了兩個mutation,咱們不知道哪一個先執行完,因此對於咱們本身也不友好,對於開發工具也很差跟蹤。
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')` // `mapMutations` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')` }) } }
有了語法糖就不要咱們每次都顯示性的寫commit了。
總之:mutation就是對應咱們用戶的一些行爲,mutation是惟一修改store中狀態的辦法。咱們須要commit來同步提交。mutation 都是同步事務~~
Action跟咱們的mutation相似,可是有兩個特色:
一、內部能夠書寫異步代碼 二、內部操做的不是state,而是經過一個與 store 實例具備相同方法和屬性的 context 對象。一般是commit 提交 mutation。
注意這裏的context不是store,而是一個相似的對象。
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } // 經過dispathc來觸發 store.dispatch('increment')
固然它也有語法糖:
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')` // `mapActions` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')` }) } }
const actions = { asyncInCrement({ commit }, n){ return new Promise(resolve => { setTimeout(() => { commit(types.TEST_INCREMENT, n); resolve(); },3000) }) } }
這種形式咱們能夠在mutation提交以後經過.then拿到通知,去作一些咱們要作的事情。
因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(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 的狀態
一、state是vuex的核心,咱們常稱爲是倉庫store,或者是組件狀態樹。
二、它是惟一數據源。咱們的全局公共狀態都防止在這個state對象中了。
三、state是響應式的。一般咱們會在組件的computed中引入咱們想要使用的state或者getters
一、getters特性咱們能夠理解爲它就是state中的計算屬性,一般用於對咱們的state的篩選和處理
二、咱們一般習慣在組件中使用state的時候就使用咱們自定義的getters
三、getters不是必定要使用,它爲了防止咱們在組件中寫冗餘的state處理計算屬性。
一、mutation是惟一修改state的方法,且必須是同步事物
一、Action跟mutation相似,可是Action中容許你寫異步代碼
二、Action中處理的不是state,而是提交mutation
一、若是請求來的數據是否是要被其餘組件公用,僅僅在請求的組件內使用,就不須要放入vuex 的state裏。二、若是被其餘地方複用,這個很大概率上是須要的,若是須要,請將請求放入action裏,方便複用,幷包裝成promise返回,