VUE組件系統(tǒng)極速入門2--vuex

看完了官網(wǎng)vuex一頭霧水的,比如vuex中的...mapState、countAlias: 'count'等。沒看過官網(wǎng)也沒事,希望對你們有幫助。
下文都是我的個(gè)人理解,官網(wǎng)的就引用了代碼,也許存在著很多錯(cuò)誤的描述或者理解,請各位請教,我會(huì)改正的。

這個(gè)坑之前就深挖了~現(xiàn)在是時(shí)候填了。
為什么要有vuex?
它是管理組件與組件通信的庫。
子組件與父組件之間通信還是很方便的。但是如果是同級組件,或者是其它的復(fù)雜情況,比如:

  • a.vue中的子組件想與b.vue中的子組件的通迅
  • a.vue想與b.vue中的子組件的通迅
  • a.vue中的子組件想與b.vue通迅
  • a.vue的子組件的子組件想與b.vue的子組件通迅
  • .....

就是為了解決了類似的問題~
我們把事件想簡單點(diǎn)吧,如果你管理那么多組件(這個(gè)改變了那個(gè)的數(shù)據(jù),那個(gè)改變了這個(gè)的數(shù)據(jù),那個(gè)組件又多了點(diǎn)什么,這個(gè)又少了點(diǎn)什么),你會(huì)怎么做呢?就說想法,不用實(shí)現(xiàn)。
我的想法是:沒有蛀牙 把整個(gè)應(yīng)用的數(shù)據(jù)全部集中起來,誰想用作顯示都無條件同意,而誰想改,改完了一定要通知所以用到這個(gè)數(shù)據(jù)顯示的組件,還不是美滋滋?
vuex也是這個(gè)意思,它一共分為以下5個(gè)部分

  • state 放數(shù)據(jù)的
  • Getter 獲取數(shù)據(jù)的
  • Mutation 同步改變數(shù)據(jù)的
  • Action 異步改變數(shù)據(jù)(利用Mutation實(shí)現(xiàn))
  • Module 可以把全局的數(shù)據(jù)倉庫分為幾個(gè)單獨(dú)的模塊,比如用戶一個(gè),文章一個(gè)。

1 state

1.1 state 定義

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

然后mutations先提一下怎么用吧(官網(wǎng)的例子,原汁原味 )

store.commit('increment')

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

然后要把這貨放在組件里,如果放入父組件中,那么子組件也可以使用。通過 this.$store。

//普通的定義
const app = new Vue({
  el: '#app',
  // 把 store 對象提供給 “store” 選項(xiàng),這可以把 store 的實(shí)例注入所有的子組件
  store,
  components: {XXX},
  template: `XXX`
})
//*.vue
export default {
  el: '#app',
  store,
  components: {XXX}
}
</script>

1.2 關(guān)于mapState

mapState的作用說到底,就是兩個(gè)作用,先說第一個(gè):別名。
上官網(wǎng)的例子,真的是要了親命了唉):

// 在單獨(dú)構(gòu)建的版本中輔助函數(shù)為 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭頭函數(shù)可使代碼更簡練
    count: state => state.count,

    // 傳字符串參數(shù) 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

先說說mapState的作用,返回一個(gè)對象。
什么樣的對象

{    
    cout: xxx //第一個(gè)
    coutAlias:xxx //第二個(gè)
    countPlusLocalState(state){xxxx}//第三個(gè)
}

我盡可能說詳細(xì)一點(diǎn),

export default {
  computed: mapState({
   /*根據(jù)箭頭函數(shù),生成的函數(shù)為
   function(state){ return state.count},
   所以count的值最后是state.count。count是個(gè)值。*/
    count: state => state.count,
    /* countAlias只是個(gè)名字,與上面的count沒有一毛錢關(guān)系,我們的大前提,
是使用的vuex里的mapstate,所以,只要我們給一個(gè)store里的屬性名,
mapstate就會(huì)把屬性名對應(yīng)的屬性返回給我們,
并用我們提供的新名字。所以,countAliae就對應(yīng)的state里的count。
   */
    countAlias: 'count',
/*注意,我強(qiáng)調(diào)一下,如果你只給屬性名,不給別名,那么就會(huì)按原屬性名返回。  比如就是一個(gè)孤零零的      'a'    你調(diào)用的時(shí)候也要調(diào)a就完事了,上面的是調(diào)countAlias  */

    // 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
    /*  箭頭函數(shù)基礎(chǔ),親,如果你看不懂為什么要這樣,請去參考下ES6的箭頭函數(shù) */
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

接下來講mapState的第二個(gè)作用:偷懶。
突然出現(xiàn)了一個(gè)...mapState,這個(gè)...就是對象展開運(yùn)算符,是ES6里的,可關(guān)鍵是為什么搞了這么一個(gè)另人費(fèi)解的東西,有什么用呢?
答:并沒有什么卵用還是有點(diǎn)用的,比如,你的compute屬性里想用store里返回的東西,一共用5個(gè)!就可以用mapstate傳5個(gè)屬性名進(jìn)去把五個(gè)搞出來再添加到compute里。
比如

computed:{
                    a1:function(){xxxxx}
}

可是你需要a2到a6,如果一個(gè)一個(gè)的寫的話,就會(huì)這樣:

  computed:{
                    a1:function(){xxxxx},
                    a2:function(){return this.$store.a2},
                    a3:function(){return this.$store.a3},
                    .......
}

有了這個(gè)...

//注意,我再強(qiáng)調(diào)一下,如果你只給屬性名,不給別名,
那么就會(huì)按原屬性名返回。所以可以這么寫:
compute:{
          a1:function(){xxxxx},
        ...mapState({'a2','a3','a4','a5','a6'})
}

然后就全有了,和上面的作用一樣,看吧,偷懶就完事了。

2 Getter

首先要審明下,做為讀書人的我,也是會(huì)罵人的?。。?!
之前很多程序員總是有些很奇怪的愛好,比如他母親的Getter。這個(gè)Getter一見到名字就是想起了被java支配的恐懼,所以不說了 所以一定要好好理解!
vuex里的getter,是在store里的一個(gè)東西,為什么需要它呢?比如,
this.$store.state.todos.filter(todo => todo.done).length這一句分別在十個(gè)函數(shù)里都出現(xiàn)了,就可以把他考慮做成一個(gè)getter函數(shù)。
把官網(wǎng)的例子搞了過來

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Getter 會(huì)暴露為 store.getters 對象:

store.getters.doneTodos // 運(yùn)行會(huì)得到 [{ id: 1, text: '...', done: true }]

Getter接受其他 getter 作為第二個(gè)參數(shù),很奇怪是吧,但是有時(shí)候需要用到getters里的別的函數(shù)。(這里定義時(shí)不支持this直接拿)

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // 得到1

在任何組件中(只要是上一級組件有store的)都可以使用:

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

getter 為什么好好的要返回一個(gè)函數(shù)?因?yàn)槟惴祷亓艘粋€(gè)函數(shù),還可以給函數(shù)傳值,讓他查些什么玩意,難道你們沒有發(fā)現(xiàn)上面的例子都只是沒有傳我們自定義的參數(shù)的?現(xiàn)在發(fā)現(xiàn)了就行~

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

還有剩下的mapGetters,嘿嘿,和上面的mapState一樣,返回屬性的規(guī)則也一樣:1 別名 2 偷懶

3 Mutation

如果 1與2都是獲取數(shù)據(jù)展示的話,那么3與4就是修改完通知了~
搞一手官網(wǎng):

更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似于事件:每個(gè) mutation 都有一個(gè)字符串的事件類型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)。這個(gè)回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會(huì)接受 state 作為第一個(gè)參數(shù)。
一個(gè)最基本的例子:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態(tài)
      state.count++
    }
  }
})
//使用:
store.commit('increment')
//注意,這里的increment 只能通過store.commit('increment')才能觸發(fā)

載荷,傳事件的時(shí)候同時(shí)傳個(gè)參數(shù)

既然能傳一個(gè)字符串的事件類型的increment,那么一定會(huì)有別的更復(fù)雜的使用方法。妥妥的,commit里還能搞個(gè)別的東西傳過去,這個(gè)就叫:載荷(payload)(我覺得可以理解成: 裝備)

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
//提交的風(fēng)格有兩種(還是從官網(wǎng)上搞的)
//風(fēng)格1:
store.commit('increment', {
  amount: 10
})
//風(fēng)格2:(個(gè)人覺得這個(gè)逼格更高一點(diǎn)點(diǎn))
store.commit({
  type: 'increment',
  amount: 10
})

使用payload也是有條件的,

  • 提前在你的 store 中初始化好所有所需屬性
  • 在對象上添加新屬性時(shí),應(yīng)該更新這個(gè)屬性,而不是再用一個(gè)新的對象
    • 使用 Vue.set(obj, 'newProp', 123)
    • 以新對象替換老對象。state.obj = { ...state.obj, newProp: 123 }

使用更短的名字使用Mutation&在組件中使用Mutation

你可以在組件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調(diào)用(需要在根節(jié)點(diǎn)注入 store)。 (官網(wǎng)原話)

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')`*/
    })
  }
}

然后官網(wǎng)也提到了使用mutations的注意事項(xiàng)
不能使用異步函數(shù)(等待時(shí)間不能太長的函數(shù),什么網(wǎng)絡(luò)連接,讀寫文件,都不是異步函數(shù))

如果你的程序中,有很多'increment'這種事件,推薦用常量保存后放在一個(gè)文件中,就像這樣:

//文件名: mutation-types.js
export const GO_TO_PICS = 'GO_TO_PICS'
export const GO_TO_NEWS = 'GO_TO_NEWS'
export const GO_TO_WE = 'GO_TO_WE'

4 Action

離4這個(gè)標(biāo)題不遠(yuǎn)處,你依稀可以看到,mutations不能使用異步函數(shù),
Action就是提交異步事件的~
Action 提交的是 mutation,Action提交的是Action ,提交的是 mutation。重要的事件要說三遍。所以,Action是在mutation外又加了一層,看一個(gè)簡單的例子。

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

context是什么玩意?有什么用?
答:他是和 store 實(shí)例具有相同方法和屬性的 context 對象。作用是[個(gè)人猜測,未驗(yàn)證]context對象作為store的輔助,也許是store的一些操作一定要通過context進(jìn)行。

調(diào)用 context.commit 提交一個(gè) mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters。

少寫一點(diǎn)(引用自網(wǎng)站,純語法):

實(shí)踐中,我們會(huì)經(jīng)常用到 ES2015 的 參數(shù)解構(gòu) 來簡化代碼(特別是我們需要調(diào)用 commit 很多次的時(shí)候):

actions: {
//這是ES6的語法
/*舉個(gè)例子:{ blowUp } = { blowUp: 10 }; 結(jié)果:{blowUp:10}
從blowUp中取一個(gè)叫blowUp的屬性。
參數(shù)本來是傳過來的context,從context中取一個(gè)commit的東西,得到  { commit : context.commit };
挺另人頭大的。
*/
  increment ({ commit }) {
    commit('increment')
  }
}

使用action
store.dispatch('increment')
但是最主要是異步調(diào)用:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

同樣的支持載荷(payload,裝備)

// 以載荷形式分發(fā)
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對象形式分發(fā)
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

官網(wǎng)上的一個(gè)更復(fù)雜的例子-購物車:

actions: {
// es6的語法,從context中取commit與state
  checkout ({ commit, state }, products) {
    // 把當(dāng)前購物車的物品備份起來 ...對象展開
    const savedCartItems = [...state.cart.added]
    // 發(fā)出結(jié)賬請求,然后樂觀地清空購物車
    commit(types.CHECKOUT_REQUEST)
    // 購物 API 接受一個(gè)成功回調(diào)和一個(gè)失敗回調(diào)
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失敗操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

上面只是定義,還有在組件中使用action的方法,不要忘記這個(gè)。
關(guān)于mapActions,作用和定義你們懂得,下面用的官網(wǎng)的例子:

你在組件中使用 this.$store.dispatch('xxx') 分發(fā) action,或者使用 mapActions 輔助函數(shù)將組件的 methods 映射為 store.dispatch 調(diào)用(需要先在根節(jié)點(diǎn)注入 store):

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')`
    })
  }
}

組合 Action(全盤搬的官網(wǎng),這個(gè)部分很好理解)

Action 通常是異步的,那么如何知道 action 什么時(shí)候結(jié)束呢?更重要的是,我們?nèi)绾尾拍芙M合多個(gè) action,以處理更加復(fù)雜的異步流程?

首先,你需要明白 store.dispatch 可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise,并且 store.dispatch 仍舊返回 Promise:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

現(xiàn)在你可以:

store.dispatch('actionA').then(() => {
  // ...
})

在另外一個(gè) action 中也可以:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

最后,如果我們利用 async / await,我們可以如下組合 action:

// 假設(shè) getData() 和 getOtherData() 返回的是 Promise

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

一個(gè) store.dispatch 在不同模塊中可以觸發(fā)多個(gè) action 函數(shù)。在這種情況下,只有當(dāng)所有觸發(fā)函數(shù)完成后,返回的 Promise 才會(huì)執(zhí)行。

5 Module

這個(gè)部分以后再說吧,想了解的可以去官網(wǎng)看看先。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • vuex是一個(gè)狀態(tài)管理模式,通過用戶的actions觸發(fā)事件,然后通過mutations去更改數(shù)據(jù)(你也可以說狀態(tài)...
    Ming_Hu閱讀 2,122評論 3 3
  • 系列文章:Vue 2.0 升(cai)級(keng)之旅Vuex — The core of Vue applic...
    6ed7563919d4閱讀 4,677評論 2 58
  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 3,035評論 0 7
  • Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)...
    白水螺絲閱讀 4,775評論 7 61
  • Vuex是什么? Vuex 是一個(gè)專為 Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,230評論 0 6

友情鏈接更多精彩內(nèi)容