Vue(1)之—— Vuex學習筆記

zhunny發表於2019-03-20

  Vuex相當於一個商店,你可以在商店上架各種各樣的商品,專案中的元件就相當於買家,他們可以購買商店中的任何商品,當一個元件買走了某樣商品,那麼商店中該樣商品的數量就會減少一個。
  Vuex有五個核心概念,State,Getter,Mutations,Actions和Module。State,Getter和Mutations是必須的,它們的關係官網有一張圖能非常清晰的說明:

Vue(1)之—— Vuex學習筆記

  1. State(狀態資料屬性,資料驅動檢視)
  2. Getters(獲取狀態中儲存的值)
  3. Mutations(修改狀態的唯一方法就是mutations,但mutations中的方法是同步的)
  4. Actions(Actions中方法是非同步的,元件中通過dispatch觸發Actions,在Actions中commit觸發mutations,然後修改State)
  5. Module(分塊管理相關狀態)

  上圖流程是這樣的,你在State中宣告瞭一個資料屬性,在某個元件中引用了它,那麼它就會被渲染render到這個元件,當這個元件想非同步的修改這個State值時,它就需要想Actions分發dispatch某個方法,在Actions非同步的觸發commit Mutations中的某個方法,而只有Mutations中的被觸發的這個方法才能修改State的值。

State

  在State中定義了一個count屬性,之後這個count可以被專案中任意的元件所使用。

state: {
    count: 1,
}
複製程式碼

  獲取State屬性的方法有三種,第一種通過this.$store訪問,後兩種都是通過vuex提供的輔助函式mapState,使用它之前需要從vuex中匯入。因為State中的屬性是響應式的,從store例項中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態。

第一種方式:通過每個元件擁有的$store訪問

computed:{
    count(){
        return this.$store.state.count
    }
}
複製程式碼

第二種方式,通過mapState訪問

import {mapState} from 'vuex'

computed:mapState{
    //1.箭頭函式
    count: state => state.count,
    //2.傳字串引數‘count’等同於state => state.count,counAlisa是別名,之前的都可以起別名
    countAlisa:'count',
    //3.傳一個函式,在顯示count值之前,還能在元件內做一些其他操作
    countLocalState(state){
      return state.count + this.num;
    }
}

//當計算屬性的方法名與state中屬性名同名時,就可以這樣簡寫
computed: mapState([
  'count'
])
複製程式碼

第三種方式,物件的展開運算子,目的是將它與區域性計算屬性混合使用

computed:{
  ...mapState({
    //這裡的操作與第二種方式是一樣的
    count:state => state.count,
    countAlisa:'count',
    countLocalState(state){
        return state.count + this.num;
    }
  })
}

//當計算屬性的方法名與state中屬性名同名時,就可以這樣簡寫
computed:{
    ...mapState([
      'count',
      'msg'
    ])
 },
複製程式碼

Getters

  可以認為是 store 的計算屬性,可以對State中的資料做一些過濾,計算長度。在state中定義一個list列表。

state: {
    lists: [
        { id: 1, msg: "hi1" },
        { id: 2, msg: "hi2" },
        { id: 3, msg: "hi3" },
        { id: 4, msg: "hi4" },
        { id: 5, msg: "hi5" }
    ]
}

getters{
    
    //引數為state,通過屬性訪問
    listLength: state =>{
        return state.lists.length;
    }
    
    listFilter(state){
        return state.lists.filter(item => item.id < 4);
    }
    
    //第二個引數還可以傳getters
    listFilterLength: (state, getters) => {
        return getters.listFilter.length
    }
    
    //通過函式訪問
    getListById: (state) => (id) => {
        return state.todos.find(item => item.id === id)
    }
}
複製程式碼

  在元件中訪問getters基本上與state相似,這裡不過多贅述,可以參考vuex官方文件。

computed:{
    listLength(){
        return this.$store.getters.listLength
    },
    getListById(){
        return this.$store.getters.getListById(2);
}
複製程式碼
import { mapGetters } from 'vuex'

computed: {
  // 使用物件展開運算子將 getter 混入 computed 物件中
    ...mapGetters([
      'listLength',
      'listFilterLength',
    ])
 }
複製程式碼

Mutations

  Mutations是改變State的唯一方法,但是它的方法必須是同步的,如果有非同步操作,那麼在stata中的資料可能和檢視中的數值不同。

mutations: {
    addNum(state, num) {
        state.count += num;
    },
    //在mutations中做非同步,在stata中的資料可能和檢視中的數值不同,payload為載荷,此方式為錯誤示範
    addCountByasync(state, payload) {
        setTimeout(() => {
            state.count += payload.num;
        }, 1000)
    },
    addCountByasync2(state, num) {
        state.count += num;
    }
},
複製程式碼

  在元件內通過methods方法提交,也是有$store方式和輔助函式的方式:

methods{
    addCountByasync(){
        //1.第一個引數是事件的名字,第二個引數是傳遞的資料
        this.$store.commit('addCountByasync', {num: 5})
    
        //以物件方式提交
        this.$store.commit({
            type:'addCountByasync',
            num:5
        })
    },
}

複製程式碼

  以下的輔助函式訪問方式參考vuex的官方文件

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')`
    })
  }
}
複製程式碼

Actions

  Actions的方法就是為了解決Mutations中不能做非同步操作的問題,所有的非同步操作放在Actions裡面,只在Mutations中修改State的值。現在元件中dispatch Actions,Actions commit Mutations。

mutations: {
    addCountByasync2(state, num) {
        state.count += num;
    }
}
actions: {
    addCountByasync({ commit }, payload) {
        setTimeout(() => {
            commit('addCountByasync2', payload.num)
        }, 1000)
    }
}
複製程式碼

在元件內的methods中分發:

methods:{
    addCountByasync2(){
      this.$store.dispatch('addCountByasync', {num: 5})
    }
}
複製程式碼

Modules

  就是根據資料的業務型別分為幾個模組,每個模組都有上述的四種物件,通過模組來呼叫,模組的用法請參考vuex手冊。

vuex開發中遇到的坑

  在給State中的某個資料物件新增新屬性時,無法更新到檢視,需要手動設定,使得資料可以驅動檢視。所以最好我們在Store中初始化好屬性,不要臨時新增。

state: {
    myProp: {

    }
},
getters: {
    myProp: (state) => {
        return state.myProp;
    }
},
mutations: {
    changeStateProp(state, name) {
        //這樣修改資料檢視是無法更新的
        // state.myProp.name = name;
        //手動設定,給State中的資料物件新增新屬性
        Vue.set(state.myProp, 'name', name)
    }
},
actions: {
    changeStateProp({ commit }, payload) {
        commit('changeStateProp', payload.name);
    }
}
複製程式碼

某個元件內:

<h2>{{ myProp }}</h2>
<button  @click="changeStateProp">修改state資料</button>

computed:{
    myProp(){
      return this.$store.getters.myProp
    }
},
methods: {
    changeStateProp(){
      this.$store.dispatch('changeStateProp', {name:'kitty'});
    }
}
複製程式碼

總結

  官網上有一段話,用來做總結:
  如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。
  該筆記是聽完某視訊vue老師講的課程之後做的筆記,如有侵權,請告知。

相關文章