Vuex學習總結

前言

 在進行復雜一點的項目開發時,咱們會發現只是普通的組件間的數據傳遞已經不足以知足咱們的需求,因此咱們須要引入Vue中管理狀態工具--Vuex

正文

與全局變量的差異

  1. 狀態存儲是響應式的,若是組件中使用了store中的值,那麼store改變時也會影響到組件狀態的改變;
  2. 改變store的惟一方法是提交(commit)mutations中的值,也就是使用commit命令去觸發mutations中的方法。
// 若是在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex)

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

store.commit('increment')// 經過commit去觸發mutations中的increment方法

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

State

state: 單一狀態樹

  在Vuex中使用state保存了所有的應用層級的狀態,咱們能夠經過store.state.[變量名]去獲取狀態值,在一般的狀況下,咱們能夠直接在每一個須要使用state的組件中引入store,可是這種方式會頻繁地在各個組件中導入,會影響性能;因此通常的解決方法是先在根實例中註冊store,該實例會註冊到子組件中,這樣的話,在子組件中咱們就能夠經過this.$store.state.[變量名]去獲取到想要的狀態。vue

// 第一種方式:在使用到state的組件中引入store

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () { // 經過計算屬性去返回狀態
      return store.state.count
    }
  }
}

// 第二種方式:在根組件的實例中,把 store 對象提供給 「store」 選項

const app = new Vue({
  el: '#app',
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count // 在子組件中只須要使用this.$store就可使用
    }
  }
}

mapState: 能夠同時得到state中的多個狀態

  前面說state的使用方法時,咱們說到能夠經過計算屬性的去拿到想要獲取的狀態,可是若是咱們要在同一個組件中獲取多個狀態時,咱們就能夠利用mapState了,下面是它的用法:vuex

// 在store實例的state中存放值
state: {
  name: '',
  age: '',
  sex: ''
}

// 在子組件的計算屬性中去獲取store中存放的值
compute: {
  ...mapState(['name'])
}

Getter

getter: store的計算屬性

  getter主要是用來存放由state派生出的一些狀態,若是不少組件都須要使用到這個狀態,就須要在每一個組件中根據state計算再計算一遍,這樣就容易形成代碼的冗餘。store中提供了一個getter屬性,能夠專門用來存放store中的state衍生出來的狀態,以下面的用法:數組

// state中存放的是todos屬性
const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, done: true },
      { id: 2, done: false }
    ]
  },
  getters: {// getters中存放的是由state派生出來,會屢次用到的值
    doneTodos: state => {// 第一個參數是state
      return state.todos.filter(todo => todo.done)
    }
  }
})

兩種訪問形式:經過屬性訪問和經過方法訪問

  1. 經過屬性訪問

 能夠經過store.getters去獲取Getter對象,而後經過訪問屬性的方式去獲取getters中的內容,好比下例:promise

store.getters.doneTodos // -> [{ id: 1, done: true }]

 getters也能夠將本身做爲參數使用,在方法中直接獲取getters中的內容:緩存

getters: {
  // 獲取doneTodos的長度
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
  1. 經過方法訪問

 能夠經過在getter中返回一個函數來給getter傳參,這個比較適用於查找store中的數組,好比下面的用法:app

getters: {
  // 經過給getTodoById傳入id來獲取對應的項
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, done: false }
  1. 兩種訪問方式的區別

 使用屬性的方式去訪問有緩存,經過方法去訪問的話,每次都會被調用一次,不會有緩存。異步

mapGetters: 輔助函數

 mapGetters和mapStates是同樣的做用,都是爲了便於在子組件中獲取多個狀態,用法也相似,這裏就很少說明了。async

Mutations

 在Vuex中,mutations的角色就至關因而vue中的methods,它能夠用來存放方法,mutations中的類型名就至關因而methods中的方法名,每一個mutation中的會有一個回調函數,可是在methods中能夠沒有返回值。模塊化

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變動狀態
      state.count++
    }
  }
})

// 經過commit去使用mutations中的方法,這也是改變state中的狀態的惟一方法
store.commit('increment')

 在commit的時候也能夠傳入額外的參數,即mutation的載荷(payload),一般這個參數會傳入一個對象,以下面的用法:函數

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

// 在commit的時候給他傳遞一個對象,這樣的好處是更加易懂明瞭
store.commit('increment', {
  amount: 10
})

// 還可使用對象的方式去提交
store.commit({
  type: 'increment',
  amount: 10
})

使用常量去代替Mutations事件類型

 在一個大型項目中,Mutations中的事件可能會比較多,這時將每種類型都用一個常量去表示,而後將這些常量放在一個靜態文件中,打開靜態文件,就能夠一目瞭然地看到Mutations中有哪些事件,好比下面的用法:

// mutation-types.js
// 在存放類型名的文件中將該類型常量拋出來
export const SOME_MUTATION = 'SOME_MUTATION'

// store.js
// 在store中引入該常量
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    [SOME_MUTATION] (state) {
      // ...
    }
  }
})

!mutation必須爲同步函數

 以前咱們說到過若是想要改變state,惟一的方法就是使用commit去改變,這樣作是由於咱們想要更明確地跟蹤state狀態的變化。若是mutation是異步函數的話,就不知道state具體是什麼時間發送變化的,這就和以前設計的初衷相悖了。還有可能有多個異步mutation時,使用commit去改變的話就分辨不出來是哪一個先進行回調,因此這也是比較麻煩的事。

Action

action和mutation的關係

 爲了解決異步回調的問題,Vuex中定義了一個相似於mutation的action,action是專門處理異步問題的,它接受一個和store變量具備相同屬性和方法的對象--context,因此能夠用該對象去調用commit進行提交。
 action和mutation有如下兩點區別:

  1. action提交的是mutation而不是直接改變state;
  2. action中能夠包含任何異步操做。
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
// 在actions中去調用mutations中的方法
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

 以前說過在action中能夠提交mutations,可是它不只僅是用來提交同步函數的,還能夠在其中執行異步操做,以下用法:

// 在actions中執行異步操做
actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

使用dispatch分發action

// 能夠經過store.dispatch去觸發action
store.dispatch('incrementAsync')

// 和commit相似,dispatch也可使用對象的方式載荷發佈
store.dispatch('incrementAsync', {
  amount: 10
})

store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

在組件中分發action

 在組件中分發action的方式有兩種:

// 使用this.$store.dispatch分發
this.$store.dispatch('incrementAsync')

// 使用mapActions將組件中的方法映射爲store.dispatch調用
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions([
      // 將this.increment()映射成this.$store.dispatch('increment')
      'increment', 
      // 將this.increment(amount)映射成this.$store.dispatch('increment', amount)
      'incrementBy'
    ]),
    
    ...mapActions([
      // 將this.add()映射成this.$store.dispatch('increment')
      add: 'increment'
    ])
  }
}

結合async和await去分發action

 使用dispatch返回的是promise對象,而且在dispatch中也能夠處理promise對象,用法以下:

actions: {
// actionA返回的是一個promise對象
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
直接處理
store.dispatch('actionA')
在action中處理
actions: {
  actionB ({ commit, dispatch }) {
    return dispatch('actionA').then(() => {
      commit('someMutation')
    })
  }  
}
綜合運用
// 假設 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

總結

 基本內容就是這麼多了,項目中目前使用到的就是這些,這篇文章只是對Vuex經常使用內容的一個總結,更多的東西能夠去看Vuex官網,若是有什麼錯誤歡迎指出哦~

相關文章
相關標籤/搜索