使用 Vuex 管理 Vue.js 状态
如果你曾经认真开发过大型单页应用,那么你可能对状态管理的概念很熟悉,尤其是 Facebook 通过 Redux 推广的 Flux 架构。在这里,我们将向你展示如何使用Vuex。
准备
安装
Vuex虽然是 Vue 的官方软件包,但并非内置。您必须决定是否在您的应用中需要它,然后通过纱或者npm。
# Yarn
$ yarn add vuex
# NPM
$ npm install vuex --save
然后,在您的应用引导程序中,确保启用Vuex插件。
import Vue from 'vue';
import Vuex from 'vuex';
import App from 'App.vue';
Vue.use(Vuex);
new Vue({
el: '#app',
render: h => h(App)
});
创建商店
为了能够利用 Vuex 提供的功能,您首先需要创建一个 store。store 本质上是一个遵循正常 Vue 反应模式的全局反应对象。它不能直接访问或修改,以确保状态一致并允许轻松跟踪更改。以下是创建 store 的方法。
export const store = new Vuex.Store({
state: {
safelyStoredNumber: 0
}
});
现在,要访问 store,你要么必须将其导入到所有组件中,要么可以将其注入到根 Vue 实例中,以便将其自动注入到应用程序中的每个其他组件中,如下所示这个。$store。在本文的其余部分我们将使用后一种方法。
import Vue from 'vue';
import Vuex from 'vuex';
import App from 'App.vue';
import { store } from './store.js';
Vue.use(Vuex);
new Vue({
store,
el: '#app',
render: h => h(App)
});
访问状态
目前,您无法对商店进行任何操作。它是您的状态的独立黑匣子,可防止任何意外操作读取或操纵它。要从商店读取数据,您需要创建一个吸气剂。
使用 Getters
getter 只是 store 中的一个函数,它接受一个状态对象并返回一个值。在你的组件中,可以通过以下方式访问它:这个。$store.getters.property作为计算属性,而不是函数。如果 getter 需要参数,它可以返回第二个接受参数的函数。
export const store = new Vuex.Store({
state: {
safelyStoredNumber: 0
},
getters: {
safelyStoredNumber: state => state.safelyStoredNumber,
storedNumberMatches(state) {
return matchNumber => {
return state.safelyStoredNumber === matchNumber;
}
}
// Shorthand:
// storedNumberMatches: state => matchNumber => state.safelyStoredNumbers === matchNumber
}
});
不过,在组件中访问 getter 的简单方法是通过 Vuex 的mapGetters辅助方法。这允许您将 getter 安装到组件中的顶级计算属性。
mapGetters如果您希望重命名组件中的 getter,则可以采用一个对象。
<template>
<p>The safely stored number: {{safelyStoredNumber}}<p>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
// Mounts the "safelyStoredNumber" getter to the scope of your component.
'safelyStoredNumber'
])
}
}
</script>
修改状态
同步突变
直接修改状态Vuex通过调用一个函数来完成突变。突变传递当前状态和可选有效负载。有效负载可以是任何对象。突变必须是同步的,并且不应返回值。它们可以通过运行直接使用this.$store.commit('mutationName',有效载荷)。
export const store = new Vuex.Store({
state: {
safelyStoredNumber: 0
},
...
mutations: {
incrementStoredNumber(state) {
state.safelyStoredNumber++;
},
setStoredNumber(state, newNumber) {
// newNumber is the payload passed in.
state.safelyStoredNumber = newNumber;
}
}
});
与 getters 一样,Vuex有一个方便的方法突变在组件中,mapMutations辅助方法。这允许您将突变作为方法安装在组件中。
<template>
<p>The safely stored number: {{safelyStoredNumber}}<p>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
...
methods: {
...mapMutations([
// Mounts the "incrementStoredNumber" mutation to `this.incrementStoredNumber()`.
'incrementStoredNumber',
// Mounts the "setStoredNumber" mutation to `this.setStoredNumber(newNumber)`.
'setStoredNumber'
])
}
}
</script>
异步操作
在更复杂的应用程序中,您可能需要执行一些修改状态的异步操作。Vuex处理这个问题行动。它们也定义在你的状态对象上,并传递整个状态上下文,这允许它们访问 getter 和提交突变。它们应该(但不是必须)返回一个指示完成状态的承诺。使用ES2017 async/await,你可以编写非常简洁但易于理解的异步行动. 动作直接在组件中使用这个。$store.dispatch('actionName',payload)。然后(响应=> {})。
要修改操作中的状态,请使用context.commit('mutationName',有效载荷). 一个动作内部允许有多个突变。
import myRemoteService from './my-remote-service.js'
export const store = new Vuex.Store({
state: {
safelyStoredNumber: 0
},
...
actions: {
async setNumberToRemoteValue(context) {
// Commits the 'setStoredNumber' mutation with the value of whatever myRemoteService.getRemoteValue() resolves through a promise.
context.commit('setStoredNumber', await myRemoteService.getRemoteValue());
return Promise.resolve();
},
}
});
如果你不熟悉异步/等待,认真地去读一下。这太棒了。简而言之,它会暂停当前函数的执行,直到等待承诺解决,允许您基本上将承诺解决用作变量,而不需要通常需要的所有额外样板。
这Vuex便捷方法行动,(可以预见地命名为地图动作) 的使用方法与突变相同。
<template>
<p>The safely stored number: {{safelyStoredNumber}}<p>
</template>
<script>
import { mapActions } from 'vuex'
export default {
...
methods: {
...mapActions([
// Mounts the "setNumberToRemoteValue" action to `this.setNumberToRemoteValue()`.
'setNumberToRemoteValue',
])
}
}
</script>
模块化
如果您只处理一小部分数据,那么单个存储就足够了,但不可避免地,在某些时候,您会希望将不断增长的操作、突变和获取器列表拆分成单独的部分。幸运的是Vuex提供了一个系统来执行此操作。模块. 尽管名字很吓人,模块其实就是一个普通的对象,状态,getters,突变, 和行动属性。您可以通过以下方式轻松创建一个:
export const myModule = {
// This makes your getters, mutations, and actions accessed by, eg: 'myModule/myModularizedNumber' instead of mounting getters, mutations, and actions to the root namespace.
namespaced: true,
state: {
myModularizedNumber: 0
},
getters: {
myModularizedNumber: state => state.myModularizedNumber
},
mutations: {
setModularizedNumber(state, newNumber) {
state.myModularizedNumber = newNumber
}
}
}
import { myModule } from './my-store-module.js';
export const store = new Vuex.Store({
modules: {
myModule
},
state: {
safelyStoredNumber: 0
},
...
});
您可以将模块嵌套在模块中,嵌套深度可随心所欲。此外,mapGetters、mapMutations 和 mapActions都可以采用第一个参数,即模块命名空间,以避免您编写这样的代码:
...mapGetters([
'myModule/nestedModule/subNestedModule/exampleGetter',
'myModule/nestedModule/subNestedModule/anotherGetter',
])
你也可以这样写:
...mapGetters('myModule/testedModule/subNestedModule', [
'exampleGetter',
'anotherGetter'
])
希望有助于理清国家管理Vuex为你!