15-Vuex基礎

Vue之vuex狀態(tài)管理

Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式没陡。

這個Vuex包含以下幾個屬性部分:

  • Action:和mutation的功能大致相同

  • State:vuex的基本數(shù)據(jù),用來存儲變量

  • Mutation:提交更新數(shù)據(jù)的方法咆蒿,必須是同步的(如果需要異步使用action)久窟。每個 mutation 都有一個字符串 的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)秩冈。

  • Module:模塊化vuex,可以讓每一個模塊擁有自己的state斥扛、mutation入问、action、getters,使得結(jié)構(gòu)非常清晰稀颁,方便管理

  • Getter:從基本數(shù)據(jù)(state)派生的數(shù)據(jù)芬失,相當于state的計算屬性

那么好的我們Actions開始講起

1.Action

Action 類似于 mutation,不同在于:

  • Action 提交的是 mutation匾灶,而不是直接變更狀態(tài)棱烂。
  • Action 可以包含任意異步操作

我們先來注冊一個action

  state: {
    count: 0
  },
  mutations: {
    add (state) {
      state.count++
    },
    decrease (state) {
      state.count--
    }
  },
  actions: {
    delayAdd (context) {
      setTimeout(() => {
          //通過context提交一個mutation
        context.commit('add')
      }, 1000)
    }
  },

Action 函數(shù)接受一個與 store 實例具有相同方法和屬性的 context 對象阶女,因此你可以調(diào)用 context.commit 提交一個 mutation颊糜,或者通過 context.statecontext.getters 來獲取 state 和 getters。

Action 通過 store.dispatch 方法或者用輔助函數(shù)mapActions觸發(fā):

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

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

很多時候我們一般使用commit比較多秃踩,但是又不想引入context,我們更多時候采用參數(shù)結(jié)構(gòu)的方式

actions: {
  delayAdd ({ commit }) {
    commit('add')
  }
}

我們一直說Action 通常是異步的衬鱼,那么如何知道 action 什么時候結(jié)束呢?更重要的是憔杨,我們?nèi)绾尾拍芙M合多個 action鸟赫,以處理更加復雜的異步流程?

store.dispatch 可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise芍秆,并且 store.dispatch 仍舊返回 Promise:

舉個栗子

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

我們?nèi)ナ褂糜|發(fā)的時候

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

或者別的地方我們還想用

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

當然了有了asyncawait以后更方便

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

actions: {
  async actionA ({ commit }) {
    // 提交getData(),等待返回結(jié)果
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

2.State

單一狀態(tài)值

我們在Vue組件中要讀取Vuex中的狀態(tài)值一般有兩種方式

第一種方式: this.$store.state

注釋:這里讀取的就是上面state進行存放的值

<template>
  <div class="home">
    <h3>This is an home page</h3>
    <div style="color: red">{{count}}</div>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: 'home',
  // 一般在計算屬性里面去監(jiān)聽處理數(shù)據(jù)值
  computed: {
    count () {
      // 通過this.$store.state去讀取存放的變量值
      return this.$store.state.count
    }
  },
}
</script>

第二種方式: mapState輔助函數(shù)

官方文檔中給的mapState函數(shù)里惯疙,給了三種獲取方式

computed: mapState({
    // 第一種我們使用箭頭函數(shù)
    count: state => state.count,
    
    // 第二種傳字符串'count'等同于上面'state => state.count'(建議使用)
    countAlias: 'count'
    
    // 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
})

我們這里寫了代碼采用了第二種方式妖啥,也是我個人經(jīng)常用的一種

<template>
  <div class="home">
    <h3>This is an home page</h3>
    <div style="color: red">{{count}}</div>
  </div>
</template>

<script>
// 第一步先引入mapState函數(shù)
import { mapState } from 'vuex'
export default {
  name: 'home',
  // 第二步去使用這個函數(shù)  
  computed: mapState({
    // 通過傳字符串的方式取值
    count: 'count'
  })
}
</script>

當然了霉颠,我們要知道es6的語言魅力很多,當映射的計算屬性的名稱與 state 的子節(jié)點名稱相同時荆虱,我們也可以給 mapState 傳一個字符串數(shù)組蒿偎。

P嗝恰!诉位!切記這是一個數(shù)組哦骑脱,不要寫成了大括號{}

computed: mapState([
    // 映射 this.count 為 store.state.count
    'count'
])

可能接下來有同學就會問,如果我既要使用計算屬性苍糠,又要用mapState呢

那么接下來我們可能會用到這個對象展開符: 嘻嘻叁丧,傳說中的點點點...

舉個栗子

computed: {
  localComputed () { /* ... */ },
  // 使用對象展開運算符將此對象混入到外部對象中
  ...mapState([
    'count'
  ])
}

3.Mutation

我們介紹這個之前我們首先要明白的是:更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation

mutation 必須是同步函數(shù)

前面講Actions的時候我們已經(jīng)在mutations里面封裝了加減函數(shù),接下來我就要說組件里面怎么去提交mutation,去更改Vuex的store中的狀態(tài)

第一種方式:組件上綁定一個方法,然后在方法里面去提交mutation

<template>
  <div class="home">
    <h3>This is an home page</h3>
    <div style="color: red">{{count}}</div>
    <button @click="add">增加count</button>
  </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'home',
  computed: {
    ...mapState({
      count: 'count'
    })
  },
  methods: {
    add () {
      // 點擊觸發(fā)提交給Mutation,觸發(fā)add方法
      this.$store.commit('add')
    }
  }
}
</script>

第二種方式:還是繼續(xù)使用輔助函數(shù)岳瞭,嘿嘿用起來以后真香拥娄,這次這個函數(shù)叫mapMutations

 methods: {
   ...mapMutations([
     'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`

     // `mapMutations` 也支持載荷(傳多個參數(shù)):
     // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
     'incrementBy' 
   ]),
  ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
  })
}

一些其他的知識點:

提交載荷(Payload)

定義:store.commit 傳入額外的參數(shù),即 mutation 的 載荷(payload)

1.比如我們在mutations中定義

mutations: {
  // 此處我們傳入多個參數(shù)
  increment (state, n) {
    state.count += n
  }
}

提交的時候就是這樣了

store.commit('increment', 10)

2.但更多時候我們載荷是一個對象

舉個栗子

mutations: {
  // 這里payload是一個對象
  increment (state, payload) {
    state.count += payload.amount
  }
}
// 第一種方式
store.commit('increment', {
  amount: 10
})
// 第二種方式
store.commit({
  type: 'increment',
  amount: 10
})

使用常量替代 Mutation 事件類型

為什么會來介紹這個呢瞳筏,我們想想一般比較大型的項目稚瘾,人員多,mutation里面的方法眾多姚炕,我們定義一個常量方法摊欠,在store.js中引用,去mutation中使用柱宦,統(tǒng)一的去管理些椒,是不是給人更清晰直觀的感受更容易知道

// 我們隨便選擇新建一個管理的js,比如叫mutation-types.js,我們在這里去新建mutation的方法捷沸,統(tǒng)一管理
export const ADD_MUTATION = 'ADD_MUTATION'
export const Delete_MUTATION = 'Delete_MUTATION'
//我們在store.js里面要去引用這個常量
import {ADD_MUTATION, Delete_MUTATION} from './mutation-types.js'

mutations: {
    // 我們可以使用 ES6 風格的計算屬性命名功能來使用一個常量作為函數(shù)名
    [ADD_MUTATION] (state) {
        // 進行增加操作啊
    }
    [Delete_MUTATION] (state) {
        // 進行刪除操作
    }
}

4.Module

使用單一狀態(tài)樹摊沉,應用的所有狀態(tài)會集中到一個比較大的對象。當應用變得非常復雜時痒给,store 對象就有可能變得相當臃腫说墨。

為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)苍柏。每個模塊擁有自己的 state尼斧、mutation、action试吁、getter棺棵、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}
// 放進store中
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

我們可以到這便是簡單基礎的模塊劃分,更多的時候熄捍,我們一般才用的是多個文件烛恤,比如a.js里面我就寫moduleA,b.js里面我就寫moduleB,然后給導出,最后統(tǒng)一在index.js引入余耽,在總模塊中使用

5.Getter

從基本數(shù)據(jù)(state)派生的數(shù)據(jù)缚柏,相當于state的計算屬性

便于多個組件使用,也是在組件的computed屬性中讀取this.$store.getters

1.通過對象來訪問

  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    // Getter接受state作為其第一個參數(shù)
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
    /** Getter 也可以接受其他 getter 作為第二個參數(shù): **/
    doneTodosCount: (state, getters) => {
      // 這里我們?nèi)プx取第一個doneTodos里面的參數(shù)
      return getters.doneTodos.length
    }
  }
  computed: {
    doneTodos () {
      // 通過this.$store.getters來獲取
      return this.$store.getters.doneTodos
    }
  },

2.通過方法來訪問

通過讓 getter 返回一個函數(shù)碟贾,來實現(xiàn)給 getter 傳參币喧。在你對 store 里的數(shù)組進行查詢時非常有用轨域。

  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    // 目的就是方便我去查詢state里面存放的值
    getTodosId: (state) => (id) => {
      return state.todos.find(todo => todo.id === id)
    }
  },

3.輔助函數(shù)mapGetters

  // 在組件中引入輔助函數(shù)mapGetters
  import {mapgetters} from 'vuex'

  // 在組件的computed里面
  computed: {
    //同名的話
    ...mapGetters([
        'doneTodos'
    ])
    //或者你想換個名字
    ...mapGetters({
      doneTodos: 'doneTodos'
    })    
  },

換名字采用的是對象的形式:所以要記得用{}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杀餐,隨后出現(xiàn)的幾起案子干发,更是在濱河造成了極大的恐慌,老刑警劉巖史翘,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枉长,死亡現(xiàn)場離奇詭異,居然都是意外死亡恶座,警方通過查閱死者的電腦和手機搀暑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跨琳,“玉大人,你說我怎么就攤上這事桐罕÷鋈茫” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵功炮,是天一觀的道長溅潜。 經(jīng)常有香客問我,道長薪伏,這世上最難降的妖魔是什么滚澜? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮嫁怀,結(jié)果婚禮上设捐,老公的妹妹穿的比我還像新娘。我一直安慰自己塘淑,他們只是感情好萝招,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著存捺,像睡著了一般槐沼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捌治,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天岗钩,我揣著相機與錄音,去河邊找鬼肖油。 笑死兼吓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的构韵。 我是一名探鬼主播周蹭,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼趋艘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凶朗?” 一聲冷哼從身側(cè)響起瓷胧,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棚愤,沒想到半個月后搓萧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡宛畦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年瘸洛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片次和。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡反肋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踏施,到底是詐尸還是另有隱情石蔗,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布畅形,位于F島的核電站养距,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏日熬。R本人自食惡果不足惜棍厌,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望竖席。 院中可真熱鬧耘纱,春花似錦、人聲如沸怕敬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽东跪。三九已至畸陡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虽填,已是汗流浹背丁恭。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斋日,地道東北人牲览。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像恶守,于是被迫代替她去往敵國和親第献。 傳聞我的和親對象是個殘疾皇子贡必,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • ### store 1. Vue 組件中獲得 Vuex 狀態(tài) ```js //方式一 全局引入單例類 // 創(chuàng)建一...
    蕓豆_6a86閱讀 726評論 0 3
  • 安裝 npm npm install vuex --save 在一個模塊化的打包系統(tǒng)中,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,927評論 0 7
  • ### store 1. Vue 組件中獲得 Vuex 狀態(tài) ```js //方式一 全局引入單例類 // 創(chuàng)建一...
    蕓豆_6a86閱讀 339評論 0 0
  • 由于Vuex的官方文檔在各個模塊之間缺乏一些過渡庸毫,另外新概念很多仔拟,使得初讀時總有些云里霧里的感覺。于是本文在官方文...
    一郭鮮閱讀 352評論 0 1
  • 本文所示范的 Docker 安裝教程是以 Ubuntu 18.04上為準飒赃,其他版本系統(tǒng)Docker安裝方法請參考D...
    春風知桺閱讀 283評論 0 0