vuex 知識點梳理

爲何會出現vuex

vuex的應用場景,你們可能或多或少知道,用來管理一些全局數據,或者多個頁面都會使用到的數據,好比,咱們項目中常見的用戶信息,一般使用vuex來管理。html

這裏,咱們思考一個問題,如何沒有vuex,還有哪些方式能夠實現一些公共數據的管理?vue

  1. 把公共數據存儲到根實例中,其餘頁面均可以經過 this.$root 來獲取根實例中的數據。
  2. 把公共數據存儲到根實例中,其餘頁面經過 provide/inject 機制來獲取根實例中的數據。

以上兩種方式,雖然能夠用來管理咱們的全局數據,可是隨着項目愈來愈複雜,全局數據愈來愈多,目前這樣的管理方式成本仍是有些高,因此,咱們須要一套系統化的,流程化的機制來管理全局數據,而vuex就是爲此而誕生的。vuex

vuex的優勢:它不只僅是一個全局數據的管理器,同時它最大的特性是支持響應式的,也就是說使用vuex管理的數據若是發生改變,那麼引入這些數據的組件都會自動刷新,vue-cli

運行機制

首先,咱們經過上圖要明白如下幾點:npm

  1. 整個流程依然是單項數據流
  2. 從State開始,這裏存儲着咱們所須要的全局變量,一樣讀取的時候,咱們也是從State裏面讀取數據。
  3. State裏面的數據變動,Vue component也就是vue組件,即頁面會進行響應式變化。
  4. 數據更新方式1: 經過commit操做,在Mutations中進行數據更新
  5. 數據更新方式2: 經過dispatch操做,在actions中進行數據更新(actions內部其實本質上也是經過commit在mutations中更新數據的)
  6. actions中一般能夠進行一些異步操做,因此若是有一些數據須要經過後端接口獲取,那麼一般將相關代碼邏輯放到actions去處理
  7. mutations中都是同步操做,若是隻有同步操做,則相關邏輯直接在mutations中處理便可

以上基本覆蓋了vuex的經常使用知識點,接下來,咱們來經過一個具體的代碼案例來深刻理解一下。後端

vuex基本使用

咱們來實現一個簡單的計數器,點擊能夠增長數字, 首先,本次代碼都在基於vue-cli3生成的項目模版去實現的。api

第一步:安裝vuex緩存

npm i vuex --save
複製代碼

第二步:引入vuexbash

//main.js
import App from './App.vue'
Vue.config.productionTip = false
//vuex的使用
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
    //全部的數據都存放在state中
    state: {
        count: 0
    },
    //mutations實現同步操做
    mutations: {
        increment (state, params) {
            state.count += params;
        }
    },
    //actions中實現一些異步操做
    actions: {
        increment ({state}, params) {
            setTimeout(() => {
                state.count += params;
            }, 3000)
        }
    },
    getters: {
        doubleCount (state) {
            return state.count * 2;
        }
    }
});
new Vue({
    store,
    render: h => h(App),
}).$mount('#app')

複製代碼
//app.vue
<template>
    <div id="app">
        <span>count: {{count}}</span>
        <button @click="addCount1">count++</button>
        <br>
        <span>doubleCount: {{doubleCount}}</span>
        <button @click="addCount2">count++</button>
    </div>
</template>

<script>

    export default {
        name: 'app',
        computed: {
            count () {
                return this.$store.state.count;
            },
            doubleCount () {
                return this.$store.getters.doubleCount;
            }
        },
        methods: {
            addCount1 () {
                this.$store.commit('increment', 2); //mutations經過commit觸發
            },
            addCount2 () {
                this.$store.dispatch('increment', 2); //actions經過dispatchc觸發
            }
        }
    }
</script>

複製代碼

經過上面的代碼,咱們要清楚如下幾點:app

  1. State: this.$store.state.xxx 取值
  2. Getters: this.$store.getters.xxx 取值
  3. Mutations: this.$store.commit('xxx') 賦值
  4. Action:this.$store.dispatch('xxx') 賦值

也就是說:咱們一般能夠經過state和getters來獲取全局數據,也能夠經過mutations和actions修改全局數據,mutations是同步操做,actions是異步操做。

1. store的建立與注入

  1. 建立store
import Vuex from 'vuex';
const store = new Vuex.Store({
    state: {},
    mutations: {}
    ...
});
複製代碼
  1. 向vue實例中注入store
new Vue({
    store,
    render: h => h(App),
}).$mount('#app')
複製代碼

問題:

  1. Vue.use(Vuex);//use方法的原理
  2. 將store注入到vue實例的原理

2. State

經過上面的學習,咱們知道了,全部狀態變量都是定義在store中的state屬性中,那麼,如何獲取state中的數據呢? //第一種方式:

export default {
    computed: {
        count () {
            return this.$store.state.count;
        },
        doubleCount () {
            return this.$store.getters.doubleCount;
        },
        number () {
            return this.$store.state.number;
        }
    },
}
即直接在computed計算屬性中返回所需數據,缺點就是:若是狀態樹愈來愈多,每一個屬性都須要咱們在computed中聲明而且返回一次,不太友好,解決方案就是mapState
複製代碼

//第二種方式:

import {mapState} from 'vuex';
export default {
    computed: mapState([
        'count',
        'doubleCount',
        'number'
    ]),
}
同時,若是想自定義別名,也能夠給mapState傳入一個對象,自定義處理,可是上面的寫法,咱們就沒法在computed聲明當前vue實例下本身的計算屬性了,解決方案就是rest運算符...
複製代碼

//第三種方式:

import {mapState} from 'vuex';
export default {
    computed: {
        ...mapState([
            'count',
            'number'
        ]),
        ...mapGetters([
            'doubleCount'
        ]),
        //也能夠自定義其餘計算屬性
    },
}
複製代碼

經過上面,咱們知道了能夠有不少種不一樣的寫法去讀取state裏面的數據,getters也相似,上面第三種方式也有體現,咱們須要知道各類寫法的優缺點,同時,在實際項目中,咱們只須要採用最優寫法便可,即第三種方式。

3. Getter

Getter與State的做用都是定義一些全局使用的數據,Getter和State的關係就相似於computed和data的關係,Getter的返回值會被緩存起來,只有它所依賴的state中的數據發生變化纔會跟着從新計算。

咱們只須要明白Getter的做用以及與State的區別便可,寫法和State相似,參考上面便可。

4. Mutation

上面咱們知道了,能夠經過state和getter來定義和讀取狀態,那麼接下來,如何修改狀態呢?記住一句話:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation.

首先,要說明一下mutation中的幾個概念:

  1. 事件類型
  2. 載荷payload

咱們在具體的代碼中說明:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    //increment就是在mutation中定義的事件類型
    increment (state, payload) {
        state.count += payload.amount
    }
  }
})

store.commit('increment', {
  amount: 10 // commit中傳的參數就是載荷
})

複製代碼

接下來,咱們要說一下在組件中mutation的幾種寫法: //第一種

export default {
    methods: {
        addCount () {
            this.$store.commit('increment', 2);           
        }
    }
}
複製代碼

//第二種方式:

import {mapMutations} from 'vuex';
export default {
     methods: {
        ...mapMutations([
            'increment'
        ]),
        addCount () {
            this.increment(2);
        }
    }
}
複製代碼

注意點:在mutation中都是同步事件,由於mutation的做用就是能夠捕捉到每一次的提交或者修改記錄,若是是異步事件,devtool很難捕捉到,這時就要用到Action了

5. Action

Action和Mutation都是用來修改狀態的,區別就是action中一般是一些異步事件,而且經過dispatch去分發事件,固然,有一點,咱們要知道actions內部也是經過提交mutation去修改數據的。

這裏,具體寫法就不說了,和mutation相似。

6. 其餘注意點:

經過上面的講解,咱們都知道了,修改state的惟一路徑就是 提交mutation,固然,若是咱們直接修改了state裏面的值,在非嚴格模式下,也是能夠生效的,可是不建議這麼作,在嚴格模式下,vue會直接報錯

還有一點:表單裏使用v-model雙向綁定的若是是state裏面的數據,這時,若是在嚴格模式下,會直接報錯的,由於數據修改完,v-model內部就默認直接修改了state裏面的數據,具體解決方案,能夠直接參考官網:vuex.vuejs.org/zh/guide/fo…

7. 總結

vuex其實自己內容是比較簡單的,可是因爲咱們引入mapState,mapGetter等map寫法以後,可能會容易產生混淆,致使感受vuex相關概念較多,沒法真正理清,這裏咱們在總結一下:

首先vuex的核心就是store,也叫倉庫,他就是一個容器,裏面包含着state,getter,mutation,action等屬性,

  1. 首先這些狀態都定義在哪裏呢?

即直接定義在state中就能夠啦

  1. 定義完之後,怎麼在組件中讀取狀態呢?

經過this.store.state 或者 this.store.getter的方式去讀取,固然爲了寫法更加間接,咱們引入了mapState和mapGetter。

  1. 定義完之後,怎麼在組件中修改狀態呢?

vuex只支持一種方式:那就是commit mutation,action內部自己也是commit mutaition, 固然,依然是爲了寫法間接,咱們又引入了mapMutations和mapActions。

經過上面的總結,咱們知道了map系列api,都只是爲了如何更簡潔的讀取和修改狀態,暫時拋開這一部分,咱們發現,其實vuex的內容其實很簡單。

原理解析

這一節,咱們主要看一下vuex的實現原理,同時,實現也能夠簡易版的vuex。

經過上面的介紹,咱們知道了vuex中的狀態state和單純的全局對象仍是不一樣的,主要體如今:

  1. vuex的狀態是響應式的
  2. vuex的狀態不能夠直接修改,必須經過提交mutation的方式去修改。

那,咱們接下來看看vuex具體是如何實現響應式的?其實內部就是經過vue的響應式機制去實現的。

下面,咱們能夠手動實現一個簡易版的vuex

import Vue from 'vue'
const Store = function Store (options = {}) {
  const {state = {}, mutations={}} = options
  this._vm = new Vue({
    data: {
      $$state: state
    },
  })
  this._mutations = mutations
}
Store.prototype.commit = function(type, payload){
  if(this._mutations[type]) {
    this._mutations[type](this.state, payload)
  }
}
Object.defineProperties(Store.prototype, { 
  state: { 
    get: function(){
      return this._vm._data.$$state
    } 
  }
});
export default {Store}
複製代碼

經過上面的代碼,咱們看到,其實vuex內部也是經過new Vue()的方式,將state存儲在vue實例的data中,從而實現響應式的。

相關文章
相關標籤/搜索