一、介紹
1.1?Vuex?是什么??
Vuex?是一個(gè)專為?Vue.js?應(yīng)用程序開發(fā)的狀態(tài)管理模式?+?庫。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。
1.2?什么是“狀態(tài)管理模式”?
這個(gè)狀態(tài)自管理應(yīng)用包含以下幾個(gè)部分:
狀態(tài),驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源;
視圖,以聲明方式將狀態(tài)映射到視圖;
操作,響應(yīng)在視圖上的用戶輸入導(dǎo)致的狀態(tài)變化。
以下是一個(gè)表示“單向數(shù)據(jù)流”理念的簡(jiǎn)單示意:
但是,當(dāng)我們的應(yīng)用遇到多個(gè)組件共享狀態(tài)時(shí),單向數(shù)據(jù)流的簡(jiǎn)潔性很容易被破壞:
-
多個(gè)視圖依賴于同一狀態(tài)。
-
來自不同視圖的行為需要變更同一狀態(tài)。
對(duì)于問題一,傳參的方法對(duì)于多層嵌套的組件將會(huì)非常繁瑣,并且對(duì)于兄弟組件間的狀態(tài)傳遞無能為力。對(duì)于問題二,我們經(jīng)常會(huì)采用父子組件直接引用或者通過事件來變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通常會(huì)導(dǎo)致無法維護(hù)的代碼。
Vuex就是把組件的共享狀態(tài)抽取出來,以一個(gè)全局單例模式管理?。
通過定義和隔離狀態(tài)管理中的各種概念并通過強(qiáng)制規(guī)則維持視圖和狀態(tài)間的獨(dú)立性,我們的代碼將會(huì)變得更結(jié)構(gòu)化且易維護(hù)。
1.3?安裝
npm install vuex@next --save
1.4?簡(jiǎn)單的Vuex使用
1.4.1?store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {},
actions: {},
})
1.4.2?main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import store from "./store";
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
store
})
1.4.3?App.vue
<template>
<div>
<my-addition></my-addition>
<p>----------------------------------</p>
<my-subtraction></my-subtraction>
</div>
</template>
<script>
import Addition from "./components/Addition";
import Subtraction from "./components/Subtraction";
export default {
data() {
return {};
},
components: {
'my-addition': Addition,
'my-subtraction': Subtraction
}
}
</script>
<style>
</style>
1.4.4?Addition.vue
<template>
<div>
<!-- 組件訪問State中數(shù)據(jù)的第一種方式 -->
<h3>當(dāng)前最新的count值為:{{$store.state.count}}</h3>
<button>+1</button>
</div>
</template>
<script>
export default {
name: "Addition",
data() {
return {};
}
}
</script>
<style scoped>
</style>
1.4.5?Subtraction.vue
<template>
<div>
<h3>當(dāng)前最新的count值為:{{$store.state.count}}</h3>
<button>-1</button>
</div>
</template>
<script>
export default {
name: "Subtraction",
data() {
return {};
}
}
</script>
<style scoped>
</style>
二、State
2.1?單一狀態(tài)樹
-
Vuex?使用單一狀態(tài)樹,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)。
-
它便作為一個(gè)“唯一數(shù)據(jù)源?(SSOT)”而存在。這也意味著,每個(gè)應(yīng)用將僅僅包含一個(gè)?store?實(shí)例。
2.2?方式一:通過$store獲取State中數(shù)據(jù)
$store.state.count
2.3?方式二:通過mapState獲取State中數(shù)據(jù)(推薦)
// 組件訪問State中數(shù)據(jù)的第二種方式--引入
import {mapState} from 'vuex'
// 將全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的計(jì)算屬性
...mapState(['count'])
// 模版中使用
<template>
<div>
<h3>當(dāng)前最新的count值為:{{count}}</h3>
<button>-1</button>
</div>
</template>
三、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ù)
3.1?方式一:使用commit觸發(fā)mutation
使用commit觸發(fā)mutation
// store.js
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
state.count++;
}
},
actions: {},
})
// Adition.vue
<template>
<div>
<!-- 組件訪問State中數(shù)據(jù)的第一種方式 -->
<h3>當(dāng)前最新的count值為:{{$store.state.count}}</h3>
<button @click="addHandler">+1</button>
</div>
</template>
<script>
export default {
name: "Addition",
data() {
return {};
},
methods: {
addHandler() {
// 這種方式是不合法的!??!
// this.$store.state.count++;
// 觸發(fā)mutation的第一種方式
this.$store.commit('add')
}
}
}
</script>
<style scoped>
</style>
帶參數(shù)的mutation
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
state.count++;
},
// 第二位就是,傳入的參數(shù)。如果是多個(gè)參數(shù)可以傳入對(duì)象
addN(state, step) {
state.count += step;
},
sub(state) {
state.count--;
},
},
actions: {},
})
// Addition.vue
<template>
<div>
<!-- 組件訪問State中數(shù)據(jù)的第一種方式 -->
<h3>當(dāng)前最新的count值為:{{$store.state.count}}</h3>
<button @click="addHandler">+1</button>
<button @click="addNHandler">+N</button>
</div>
</template>
<script>
export default {
name: "Addition",
data() {
return {};
},
methods: {
addHandler() {
// 這種方式是不合法的?。?!
// this.$store.state.count++;
// 觸發(fā)mutation的第一種方式
this.$store.commit('add')
},
addNHandler() {
this.$store.commit('addN', 3)
}
}
}
</script>
<style scoped>
</style>
3.2?方式二:使用mapMutation觸發(fā)mutation(推薦)
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
state.count++;
},
addN(state, step) {
state.count += step;
},
sub(state) {
state.count--;
},
subN(state, step) {
state.count -= step;
},
},
actions: {},
})
Subtraction.vue
<template>
<div>
<h3>當(dāng)前最新的count值為:{{count}}</h3>
<button @click="subHandler">-1</button>
<button @click="subNHandler">-N</button>
</div>
</template>
<script>
// 組件訪問State中數(shù)據(jù)的第二種方式--引入
import {mapState, mapMutations} from 'vuex'
export default {
name: "Subtraction",
data() {
return {};
},
computed: {
// 將全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的計(jì)算屬性
...mapState(['count'])
},
methods: {
...mapMutations(['sub', 'subN']),
// 將全局mutations函數(shù)映射為組件中的函數(shù)
subHandler() {
this.sub();
},
subNHandler() {
this.subN(3)
}
}
}
</script>
<style scoped>
</style>
四、Action
Action的作用是執(zhí)行異步函數(shù),因?yàn)閙utation中無法執(zhí)行異步函數(shù)。在mutation中使用異步函數(shù)會(huì)導(dǎo)致state的狀態(tài)無法被及時(shí)追蹤導(dǎo)致代碼異常?。?!
4.1?方式一:使用dispatch調(diào)用Action中的異步函數(shù)
4.1.1?store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
// setTimeout(() => {
// // 不要在mutations中執(zhí)行異步操作,會(huì)造成vuex存儲(chǔ)狀態(tài)不可追蹤
// state.count++;
// }, 1000)
state.count++;
},
addN(state, step) {
state.count += step;
},
sub(state) {
state.count--;
},
subN(state, step) {
state.count -= step;
},
},
actions: {
// context: 可以理解為當(dāng)前的Vuex.Store實(shí)例對(duì)象
addAsync(context) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('add')
}, 1000)
},
addNAsync(context, step) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('addN', step)
}, 1000)
}
},
})
4.1.2?Addition.vue
<template>
<div>
<!-- 組件訪問State中數(shù)據(jù)的第一種方式 -->
<h3>當(dāng)前最新的count值為:{{$store.state.count}}</h3>
<button @click="addHandler">+1</button>
<button @click="addNHandler">+N</button>
<button @click="addHandlerAsync">+1 Async</button>
<button @click="addNHandlerAsync">+N Async</button>
</div>
</template>
<script>
export default {
name: "Addition",
data() {
return {};
},
methods: {
addHandler() {
// 這種方式是不合法的?。?!
// this.$store.state.count++;
// 觸發(fā)mutation的第一種方式
this.$store.commit('add')
},
addNHandler() {
this.$store.commit('addN', 3)
},
addHandlerAsync() {
// 這里的 dispatch 專門用來觸發(fā)action函數(shù)
this.$store.dispatch('addAsync')
},
addNHandlerAsync() {
// 這里的 dispatch 專門用來觸發(fā)action函數(shù)
this.$store.dispatch('addNAsync', 3)
}
}
}
</script>
<style scoped>
</style>
4.2?方式二:使用mapAction調(diào)用Action中的異步函數(shù)
4.2.1?store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
// setTimeout(() => {
// // 不要在mutations中執(zhí)行異步操作,會(huì)造成vuex存儲(chǔ)狀態(tài)不可追蹤
// state.count++;
// }, 1000)
state.count++;
},
addN(state, step) {
state.count += step;
},
sub(state) {
state.count--;
},
subN(state, step) {
state.count -= step;
},
},
actions: {
// context: 可以理解為當(dāng)前的Vuex.Store實(shí)例對(duì)象
addAsync(context) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('add')
}, 1000)
},
addNAsync(context, step) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('addN', step)
}, 1000)
},
subAsync(context) {
setTimeout(() => {
context.commit('sub')
}, 1000)
},
subNAsync(context, step) {
setTimeout(() => {
context.commit('subN', step)
}, 1000)
}
},
})
4.2.2??Subtraction.vue
<template>
<div>
<h3>當(dāng)前最新的count值為:{{count}}</h3>
<button @click="subHandler">-1</button>
<button @click="subNHandler">-N</button>
<button @click="subHandlerAsync">-1 Async</button>
<button @click="subNHandlerAsync">-N Async</button>
</div>
</template>
<script>
// 組件訪問State中數(shù)據(jù)的第二種方式--引入
import {mapState, mapMutations, mapActions} from 'vuex'
export default {
name: "Subtraction",
data() {
return {};
},
computed: {
// 將全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的計(jì)算屬性
...mapState(['count'])
},
methods: {
...mapMutations(['sub', 'subN']),
...mapActions(['subAsync', 'subNAsync']),
// 將全局mutations函數(shù)映射為組件中的函數(shù)
subHandler() {
this.sub();
},
subNHandler() {
this.subN(3)
},
subHandlerAsync() {
this.subAsync();
},
subNHandlerAsync() {
this.subNAsync(3)
}
}
}
</script>
<style scoped>
</style>
五、Getters
Vuex?允許我們?cè)?store?中定義“getter”(可以認(rèn)為是?store?的計(jì)算屬性)。就像計(jì)算屬性一樣,getter?的返回值會(huì)根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算。
5.1?創(chuàng)建Getter方法
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
// setTimeout(() => {
// // 不要在mutations中執(zhí)行異步操作,會(huì)造成vuex存儲(chǔ)狀態(tài)不可追蹤
// state.count++;
// }, 1000)
state.count++;
},
addN(state, step) {
state.count += step;
},
sub(state) {
state.count--;
},
subN(state, step) {
state.count -= step;
},
},
actions: {
// context: 可以理解為當(dāng)前的Vuex.Store實(shí)例對(duì)象
addAsync(context) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('add')
}, 1000)
},
addNAsync(context, step) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的數(shù)據(jù)
// 必須通過 context.commit() 觸發(fā)某個(gè) mutations 才行
context.commit('addN', step)
}, 1000)
},
subAsync(context) {
setTimeout(() => {
context.commit('sub')
}, 1000)
},
subNAsync(context, step) {
setTimeout(() => {
context.commit('subN', step)
}, 1000)
}
},
getters: {
showNum(state) {
return '當(dāng)前最新的數(shù)量是【' + state.count + '】';
}
}
})
5.2?方法一:$store.getter調(diào)用
<template>
<div>
<!-- 組件訪問State中數(shù)據(jù)的第一種方式 -->
<h3>{{$store.getters.showNum}}</h3>
<button @click="addHandler">+1</button>
<button @click="addNHandler">+N</button>
<button @click="addHandlerAsync">+1 Async</button>
<button @click="addNHandlerAsync">+N Async</button>
</div>
</template>
<script>
export default {
name: "Addition",
data() {
return {};
},
methods: {
addHandler() {
// 這種方式是不合法的!??!
// this.$store.state.count++;
// 觸發(fā)mutation的第一種方式
this.$store.commit('add')
},
addNHandler() {
this.$store.commit('addN', 3)
},
addHandlerAsync() {
// 這里的 dispatch 專門用來觸發(fā)action函數(shù)
this.$store.dispatch('addAsync')
},
addNHandlerAsync() {
// 這里的 dispatch 專門用來觸發(fā)action函數(shù)
this.$store.dispatch('addNAsync', 3)
}
}
}
</script>
<style scoped>
</style>
5.3?方法二:mapGetters方式調(diào)用
<template>
<div>
<h3>{{showNum}}</h3>
<button @click="subHandler">-1</button>
<button @click="subNHandler">-N</button>
<button @click="subHandlerAsync">-1 Async</button>
<button @click="subNHandlerAsync">-N Async</button>
</div>
</template>
<script>
// 組件訪問State中數(shù)據(jù)的第二種方式--引入
import {mapState, mapMutations, mapActions, mapGetters} from 'vuex'
export default {
name: "Subtraction",
data() {
return {};
},
computed: {
// 將全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的計(jì)算屬性
...mapState(['count']),
// 將全局的getters,映射為當(dāng)前組件的計(jì)算屬性
...mapGetters(['showNum'])
},
methods: {
...mapMutations(['sub', 'subN']),
...mapActions(['subAsync', 'subNAsync']),
// 將全局mutations函數(shù)映射為組件中的函數(shù)
subHandler() {
this.sub();
},
subNHandler() {
this.subN(3)
},
subHandlerAsync() {
this.subAsync();
},
subNHandlerAsync() {
this.subNAsync(3)
}
}
}
</script>
<style scoped>
</style>
六、其他
6.1?modules
Module | Vuex文章來源:http://www.zghlxwxcb.cn/news/detail-806866.html
Vuex?允許我們將?store?分割成模塊(module)。每個(gè)模塊擁有自己的?state、mutation、action、getter、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割:文章來源地址http://www.zghlxwxcb.cn/news/detail-806866.html
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 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
到了這里,關(guān)于VueSupercharge 精通指南:構(gòu)建超級(jí)狀態(tài)管理 Vue.js 應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!