简介:
Vuex是Vue.js的官方状态管理库,用于管理应用程序的状态。本篇博客将介绍如何安装Vuex、创建Vuex Store,并在Vue应用中使用Vuex来访问和修改状态。同时,我们将提供一个实例演示,以更具体地展示Vuex的用法。
正文:
安装Vuex:
首先,我们使用npm或yarn在项目的根目录下安装Vuex:
```
npm install vuex
```
创建Vuex Store:
在项目中创建一个新的JavaScript文件,例如store.js
,并编写以下代码:
```js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment(context) {
context.commit('increment')
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
export default store
```
在Vue应用中使用Vuex:
在Vue应用的入口文件(一般是main.js
)中导入并使用Vuex Store:
```javascript
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
store,
render: h => h(App)
}).$mount('#app')
```
在组件中访问和修改状态:
现在,我们可以在组件中访问和修改Vuex Store中的状态。在计算属性和方法中使用this.$store.state
来访问状态,使用this.$store.commit()
来触发状态的变更。
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count
},
doubleCount() {
return this.$store.getters.doubleCount
}
},
methods: {
increment() {
this.$store.dispatch('increment')
}
}
}
</script>
在上述示例中,我们使用this.$store.state.count
访问状态,使用this.$store.getters.doubleCount
获取计算属性的值,通过this.$store.dispatch('increment')
来触发状态的变更。
mapState 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键:
在组件的computed选项中,使用mapState函数将Vuex状态映射为计算属性。你可以传递一个数组或者对象给mapState函数。
- 数组语法:
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
computed: mapState(['count'])
- 对象语法:
computed: mapState({
count: 'count'
})
上述两种语法只能提供映射,不能计算.如果想要实现计算,需要这样写:
computed: {
...mapState(['count']),
doubleCount() {
return this.count * 2
}
}
- 更高级的对象语法:
computed: mapState({
count: state => state.count,
// 或者使用箭头函数
doubleCount: state => state.count * 2
})
上述代码可以对状态进行更高级的处理,例如对状态进行计算或者过滤。
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
Getter
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
以下是Getter的用法和示例:
- 定义Getter: 在Vuex的Store中,通过定义getters对象来声明Getter。
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: 'Buy groceries', completed: false },
{ id: 2, text: 'Clean the house', completed: true },
{ id: 3, text: 'Walk the dog', completed: false }
]
},
getters: {
// Getter用于计算未完成的任务数量
unfinishedTasks(state) {
return state.todos.filter(todo => !todo.completed).length
}
}
})
在上述示例中,我们定义了一个名为unfinishedTasks的Getter,用于计算未完成的任务数量。
- 在组件中使用Getter: 在组件中使用Getter可以通过this.$store.getters来访问。Getter会作为Store的一个属性暴露出来。
<template>
<div>
<p>Unfinished Tasks: {{ unfinishedTasks }}</p>
</div>
</template>
<script>
export default {
computed: {
unfinishedTasks() {
return this.$store.getters.unfinishedTasks
}
}
}
</script>
在上述示例中,我们在组件的计算属性中使用this.$store.getters.unfinishedTasks来获取未完成的任务数量。
- 在辅助函数中使用Getter: 我们还可以使用mapGetters辅助函数将Getter映射为组件的计算属性,以简化代码。
<template>
<div>
<p>Unfinished Tasks: {{ unfinishedTasks }}</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['unfinishedTasks'])
}
}
</script>
在上述示例中,我们使用mapGetters将Getter映射为计算属性,可以直接在模板中使用unfinishedTasks。
Getter的优势:
- 提供了一种集中计算和过滤状态的方式,避免了重复计算。
- 可以将复杂的逻辑封装在Getter中,使组件更加简洁和可维护。
- Getter是响应式的,当Getter所依赖的状态发生变化时,Getter会自动更新。
总结: Getter是Vuex中用于计算和过滤状态的一种机制,类似于组件中的计算属性。通过定义Getter并在组件中使用,我们可以方便地获取和重用派生状态,提高代码的可读性和可维护性。使用Getter可以有效地管理和操作Store中的状态数据。
Action是Vuex中用于处理异步操作的对象,它可以包含任意的异步操作、调用API请求、提交Mutation等。Action提供了一种将逻辑和异步操作从组件中分离的方式,使得代码更加清晰、可维护,并且方便进行单元测试。
Action的用法和示例:
- 定义Action: 在Vuex的Store中,通过定义actions对象来声明Action。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync(context) {
setTimeout(() => {
context.commit('increment')
}, 1000)
}
}
})
在上述示例中,我们定义了一个名为incrementAsync的Action,它会在1秒后调用commit方法来触发incrementMutation。
- 在组件中使用Action: 在组件中使用Action可以通过this.$store.dispatch来触发。Action会作为Store的一个方法暴露出来。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
incrementAsync() {
this.$store.dispatch('incrementAsync')
}
}
}
</script>
在上述示例中,我们在组件的方法中使用this.$store.dispatch来触发incrementAsyncAction。
- 在辅助函数中使用Action: 我们还可以使用mapActions辅助函数将Action映射为组件的方法,以简化代码。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed: {
count() {
return this.$store.state.count
},
},
methods: {
...mapActions(['incrementAsync'])
}
}
</script>
在上述示例中,我们使用mapActions将Action映射为组件的方法,可以直接在模板中使用incrementAsync方法。
Action的优势:
- 处理异步操作:Action适用于处理异步操作,例如API请求、定时器、延迟等。它们不会阻塞主线程,可以让应用保持响应性。
- 提交Mutation:Action可以通过commit方法提交Mutation,保持了对状态变更的一致性和追踪性。
- 组织复杂逻辑:Action可以包含多个异步操作、条件判断、API请求等,使得逻辑更加清晰、可维护,并且可以重用。
- 方便测试:由于Action是纯函数,不依赖组件实例,因此可以更容易地进行单元测试和模拟。
总而言之,Action提供了一种组织和处理异步操作的方式,使得代码更加清晰、可维护,并且能够更好地管理应用状态的变化。它是Vuex中重要的概念之一,帮助我们构建复杂的应用程序。
Module的用法和示例:
Module是Vuex中用于组织和管理状态的模块化机制。它允许我们将大型的Vuex应用程序拆分为更小、可维护的模块,每个模块都具有自己的状态、mutations、actions、getters等。
通过使用Module,我们可以将相关的状态和逻辑组合在一起,提高代码的可读性、可维护性,并支持团队协作开发。
- 定义Module: 在Vuex的Store中,通过使用modules选项来定义Module。
const store = new Vuex.Store({
modules: {
cart: {
state: {
items: []
},
mutations: {
addItem(state, item) {
state.items.push(item)
}
},
actions: {
addToCart(context, item) {
context.commit('addItem', item)
}
},
getters: {
cartItemsCount(state) {
return state.items.length
}
}
}
}
})
在上述示例中,我们定义了一个名为cart的Module,它包含了items状态、addItemMutation、addToCartAction和cartItemsCountGetter。
- 在组件中使用Module: 在组件中使用Module的状态、Mutation、Action和Getter时,需要通过模块路径进行访问。
<template>
<div>
<p>Cart Items: {{ cartItemsCount }}</p>
<button @click="addToCart">Add to Cart</button>
</div>
</template>
<script>
export default {
computed: {
cartItemsCount() {
return this.$store.state.cart.items.length
}
},
methods: {
addToCart() {
this.$store.dispatch('cart/addToCart', { name: 'Product 1', price: 10 })
}
}
}
</script>
在上述示例中,我们在组件中使用
this.$store.state.cart.items
来访问cart模块的状态,并使用this.$store.dispatch(‘cart/addToCart’) 来触发addToCartAction。
- 在辅助函数中使用Module: 我们还可以使用namespaced选项和mapState、mapMutations、mapActions、mapGetters等辅助函数简化对Module的访问。
<template>
<div>
<p>Cart Items: {{ cartItemsCount }}</p>
<button @click="addToCart">Add to Cart</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState('cart', ['cartItemsCount'])
},
methods: {
...mapActions('cart', ['addToCart'])
}
}
</script>
在上述示例中,我们使用mapState将cartItemsCount映射为组件的计算属性,并使用mapActions将addToCart映射为组件的方法。
例子
Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
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: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
通过使用Module,我们可以将应用状态拆分为更小的模块,使得代码结构更清晰、可维护。每个Module都可以独立开发和测试,且可以嵌套使用,形成层次化的状态管理结构。这对于大型应用程序和团队协作开发非常有益。
实例演示:
在本示例中,我们将创建两个组件:Counter.vue和Button.vue。Counter组件用于显示计数值,Button组件用于触发计数器的增加。
<!-- Counter.vue -->
<template>
<div>
<p>Count: {{ count }}</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['count'])
}
}
</script>
<!-- Button.vue -->
<template>
<div>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(['increment'])
}
}
</script>
创建根组件:
在App.vue中,使用Counter和Button组件,并通过Vuex共享状态。
<template>
<div>
<h1>Counter App</h1>
<Counter />
<Button />
</div>
</template>
<script>
import Counter from './Counter.vue'
import Button from './Button.vue'
export default {
components: {
Counter,
Button
}
}
</script>
在这个示例中,Counter组件通过计算属性使用mapState
辅助函数将Vuex的状态映射为组件的数据。Button组件通过方法使用mapActions
辅助函数将Vuex的动作映射为组件的方法。文章来源:https://uudwc.com/A/dMNq1
这样,当我们在浏览器中访问应用时,将会看到一个计数器和一个按钮。点击按钮会增加计数值,并实时更新到Counter组件上。文章来源地址https://uudwc.com/A/dMNq1