今天來學習一下vuex
- 前言
- 什么是vuex?
- 使用前奏
- 五大核心概念
- 一個store例子
- State
- Getter
- Mutations
- Mutations的提交方式
- Action
- 一個例子
- action的提交方式
- 組合action
- Modules
- 模塊的區域狀態
- 一個vuex的應用實體
前言
為什么會出現vuex?
- 1.如何讓多個vue組件共享狀態?
- 2.vue組件間如何通訊?
通常,在專案不是很復雜的時候,我們會利用全域事件總線解決,但是隨著復雜度的提升,這些代碼將變得難以維護,因此,我們需要一種更加好用的解決方案,于是,vuex誕生了!
什么是vuex?
- Vuex是一個專門為Vue.js應用設計的狀態管理架構,統一管理和維護各個vue組件的可變化狀態(vue組件里面的某些data)
- 它采用集中式存盤管理應用所有組件的狀態,并以回應的規則保證狀態以一種課預測的方式發生變化
- Vue五個核心概念,state,getters,mutations,action,modules


使用前奏
- 1.npm安裝
npm install vuex - 2.Vue.use()
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
五大核心概念
- state
- getters
- mutations
- actions
- modules
一個store例子
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
現在,你可以通過 store.state 來獲取狀態物件,以及通過 store.commit 方法觸發狀態變更:
store.commit('increment')
console.log(store.state.count) // -> 1
在App.vue檔案中添加代碼,在templete模板中添加一個按鈕和點擊事件
<button v-on:click="addClick">加</button>
在
import store from './vuex/store'
methods:
{
addClick:function(){
store.commit('increment')
console.log(store.state.count) // -> 1
}
}
State
state是一個全域的狀態存盤,資料會存盤在其中,vue組件可以直接訪問其中的值,但是只可以讀,不可以進行寫操作
Getter
有些時候我們需要對獲取的資料進行加工,獲取資料的一部分或者某些屬性,而不是直接獲取state中的資料,這時候可以通過getter定義函式,回傳對應的資料
Mutations
mutations是vuex中唯一一個可以修改資料的地方,mutations可以定義事件函式,在vue組件中可以通過commit發射事件,呼叫函式,需要注意的是,mutations中的操作必須是同步的,不可以存在異步操作的情況
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation,Vuex 中的 mutations 非常類似于事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回呼函式 (handler),這個回呼函式就是我們實際進行狀態更改的地方,并且它會接受 state 作為第一個引數:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 改變狀態
state.count++
}
}
})
你不能直接呼叫一個 mutation 回呼函式,要喚醒一個 mutation,你呼叫 store.commit 方法(引數為回呼函式名):
store.commit('increment')
mutation回呼函式的第一個引數始終為store,你可以向 store.commit 傳入額外的引數,即 mutation 的 載荷(playload):
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 10)
在大多數情況下,載荷應該是一個物件,這樣可以包含多個欄位并且記錄的 mutation 會更易讀:
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
Mutations的提交方式
提交 mutation 的另一種方式是直接使用包含 type 屬性的物件:
store.commit({
type: 'increment',
amount: 10
})
當使用物件風格的提交方式,整個物件都作為載荷傳給 mutation 函式,因此 handler 保持不變:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
你可以在組件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 輔助函式將組件中的 methods 映射為 store.commit 呼叫(需要在根節點注入 store),
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment' // 映射 this.increment() 為 this.$store.commit('increment')
]),
...mapMutations({
add: 'increment' // 映射 this.add() 為 this.$store.commit('increment')
})
}
}
Action
和mutation比較相似,不同的是cations中不直接修改state,而是通過commit呼叫mutations修改資料,而且actions中可以存在異步處理邏輯
- action提交的是mutation,而不是直接變更狀態
- action可以包含任意異步操作
可以把mutation比作倉庫的管理員,負責倉庫管理,而把action比作領導,可以命令倉庫管理員作操作,但不會親自動手,
一個例子
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
actions 的第一個引數是 context,它向外暴露一組與 store 實體相同的方法/屬性,所以可以直接呼叫 context.commit 或者訪問 context.state 或者 context.getters ,我們通常使用 es6 的引數解構來簡化我們的代碼,直接寫成{ commit }
actions: {
increment ({ commit }) {
commit('increment')
}
}
Action 通過 store.dispatch 方法觸發:store.dispatch(‘increment’)
action多此一舉嗎?
mutation 必須同步執行這個限制么?Action 就不受約束!我們可以在 action 內部執行異步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
action的提交方式
- 1.載荷形式分發
store.dispatch('incrementAsync', {
amount: 10
})
- 2.以物件形式分發
store.dispatch({
type: 'incrementAsync',
amount: 10
})
- 3.在組件中分發
在組件中使用this.$store.dispatch('xxx')分發 action,或者使用mapActions輔助函式將組件的 methods 映射為 store.dispatch 呼叫(需要先在根節點注入 store):
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment' // 映射 this.increment() 為 this.$store.dispatch('increment')
]),
...mapActions({
add: 'increment' // 映射 this.add() 為 this.$store.dispatch('increment')
})
}
}
組合action
action通常是異步的,那么如何知道action什么時候接觸呢?如何組合多個action呢?
第一件事是store.dispatch的回傳的是被觸發的action函式的回傳值,因此你可以在action中回傳Promise:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
就可以使用then()
store.dispatch('actionA').then(() => {
// ...
})
在另一個action中也可以
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
最后,如果我們利用 [async / await] 這個 JavaScript 即將到來的新特性,我們可以像這樣組合 action:
假設 getData() 和 getOtherData() 回傳的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
Modules
使用單一狀態樹,導致應用的所有狀態集中到一個很大的物件,但是,當應用變得很大時,store物件會變得臃腫不堪,
為了解決以上問題,Vuex運行將store分割到多個模塊(module),每個模塊擁有自己的state,mutation,action,getters,甚至時嵌套子模塊—從上至下進行類似的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態
模塊的區域狀態
對于模塊內部的 mutation 和 getter,接收的第一個引數是模塊的區域狀態,
const moduleA = {
state: { count: 0 },
mutations: {
increment: (state) {
// state 模塊的區域狀態
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
同樣,對于模塊內部的 action,context.state 是區域狀態,根節點的狀態是 context.rootState:
const moduleA = {
// ...
actions: {
incrementIfOdd ({ state, commit }) {
if (state.count % 2 === 1) {
commit('increment')
}
}
}
}
對于模塊內部的 getter,根節點狀態會作為第三個引數:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
一個vuex的應用實體
- store.js
export default new Vuex.Store({
state: {
messages: []
},
actions: {
newMessage ({commit}, msg) {
commit('NEW_MESSAGE', msg)
}
},
mutations: {
NEW_MESSAGE (state, msg) {
state.messages.push(msg)
}
}
})
- main.js
import Vue from 'vue'
import App from './App.vue'
import store from './vuex/store'
new Vue({
el: '#app',
store,
render: h => h(App)
})
- client.vue
<template>
<div>
<h1>{{ clientid }}</h1>
<div>
<ul>
<li v-for="message in messages">
<label>{{ message.sender }}:</label> {{ message.text }}
</li>
</ul>
<div>
<input v-model="msg" placeholder="Enter a message, then hit [enter]" @keyup.enter="trySendMessage">
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
msg: ''
}
},
props: ['clientid'],
computed:{
...mapState({
messages: state => state.messages
})
},
methods: {
trySendMessage() {
this.newMessage({
text: this.msg,
sender: this.clientid
})
this.resetMessage()
},
resetMessage() {
this.msg = ''
},
...mapActions(['newMessage'])
}
}
</script>
<style>
</style>
- App.vue
<div>
<client clientid="Client A"></client>
</div>
<div>
<client clientid="Client B"></client>
</div>
<script>
import client from './components/Client.vue'
import store from './vuex/store'
export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
components:{client}
}
</script>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/305708.html
標籤:其他
下一篇:手寫一個通用事件監聽函式
