看完这个,再也不怕 vuex 了
VueX 是一个专门为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理所有的组件的状态,并以相应的规则保证状态以一种预期的方式发生变化。
如果你对 "状态管理模式" 这个术语感到困惑,可以把它想象成一个全局的数据存储区,就像你的应用的数据仓库。
让我们通过一个简单的例子来理解这个概念。
假设你正在建设一个购物网站,用户可以在网站的多个页面上添加商品到购物车。在这种情况下,购物车的状态(例如,购物车里有哪些商品)需要被多个组件共享和修改。
如果没有 Vuex,你可能需要通过父子组件间的事件和 props 来传递状态。但是随着应用的增长,这将变得越来越复杂。这就是 Vuex 的用武之地。
在 Vuex 中,你得记住以下几个核心概念:
State
状态是存储在Vuex中的数据,可以看作是所有组件的数据源。
在Vuex中,状态是响应式的,如果Vue组件从Vuex中读取状态,那么当状态发生改变时,相应的组件也会更新。
例如,我们在 Vuex 存储一个用户登录的状态:
const store = new Vuex.Store({
state: {
isLoggedIn: false
}
})
Getters
Getter是Vuex中的计算属性,可以用来对State进行过滤和计算。Getter的结果会根据它的依赖被缓存起来,只有当它的依赖值发生改变才会被重新计算。
例如,我们想要根据 isLoggedIn
的状态显示不同的信息:
const store = new Vuex.Store({
state: {
isLoggedIn: false
},
getters: {
loginStatus: state => state.isLoggedIn ? "已登录" : "未登录"
}
})
我们可以用 this.$store.getters.loginStatus
来获取。
Mutations
Mutation是改变Vuex中State的唯一方法。
每个mutation都有一个字符串类型的事件类型和一个回调函数,回调函数就是我们实际进行状态更改的地方。
例如,我们可以定义一个 mutation 来改变 isLoggedIn
的状态:
const store = new Vuex.Store({
state: {
isLoggedIn: false
},
mutations: {
login: state => state.isLoggedIn = true,
logout: state => state.isLoggedIn = false
}
})
在组件中,我们可以通过 this.$store.commit('login')
来触发一个 mutation。
Actions
Action类似于Mutation,但是是用来执行异步操作的。
在 actions
中,你不能直接修改状态。你需要调用 mutations
来修改状态。
actions
可以处理异步操作,而 mutations
只能同步执行。
例如,我们可以定义一个 action 来模拟一个异步的登录过程:
mutations: {
login: state => state.isLoggedIn = true
},
actions: {
asyncLogin: context => {
setTimeout(() => {
context.commit('login')
}, 1000)
}
}
这段代码里,我们有一个 login
的 mutation
,它会把 isLoggedIn
的状态设置为 true
。
我们也有一个名为 asyncLogin
的 action
,它使用 setTimeout
来模拟一个异步的操作。
在 asyncLogin
的 action
里,我们使用了 context.commit
方法来触发 login
的 mutation
。context
对象提供了一组同 Vuex store 实例具有相同方法和属性的方法,所以你可以调用 context.commit
来提交一个 mutation
。
而当我们在组件里使用 this.$store.dispatch('asyncLogin')
时,就会触发 asyncLogin
这个 action
。asyncLogin
在一秒后调用了 login
这个 mutation
,从而改变了 isLoggedIn
这个状态。
总结来说,action
和 mutation
的联系是:action
负责处理异步操作,在需要修改状态时,会调用 mutation
来进行状态的修改。
Modules
当应用变得非常复杂时,store 对象就有可能变得非常臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
例如,我们可以创建一个用户模块来处理所有的用户相关的状态操作:
const userModule = {
state: {
isLoggedIn: false,
},
mutations: {
login: (state) => (state.isLoggedIn = true),
logout: (state) => (state.isLoggedIn = false),
},
actions: {
asyncLogin: (context) => {
setTimeout(() => {
context.commit("login");
}, 1000);
},
},
getters: {
loginStatus: (state) => (state.isLoggedIn ? "已登录" : "未登录"),
},
};
const store = new Vuex.Store({
modules: {
user: userModule,
},
});
// 在组件中,我们可以使用 `this.$store.state.user.isLoggedIn` 来获取模块中的状态
// 使用 `this.$store.getters['user/loginStatus']` 来获取模块中的 getter
// 使用 `this.$store.commit('user/login')` 来触发模块中的 mutation
// 使用 `this.$store.dispatch('user/asyncLogin')` 来触发模块中的 action
多模块的使用
一般情况下,我们会为每一个模块创建一个单独的文件,这样能让代码更加的清晰和容易管理。例如,你可能会有 user.js
、product.js
、cart.js
等文件,每个文件都导出一个模块的对象。
然后,你可以在你的主 store 文件中引入这些模块。假设你的主 store 文件是 index.js
,那么你可以这样做:
import Vue from 'vue';
import Vuex from 'vuex';
// 引入模块
import user from './modules/user';
import product from './modules/product';
import cart from './modules/cart';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user,
product,
cart
}
});
在这个例子中,./modules/user
、./modules/product
和 ./modules/cart
分别是 user、product 和 cart 模块的路径。
引入之后,我们将这些模块注册到 Vuex store 的 modules
属性中,Vuex 会自动将这些模块的 state、mutations、actions 和 getters 集成到主 store 中。
Vuex 中的辅助函数
mapState
, mapGetters
, mapActions
和 mapMutations
都是 Vuex 提供的辅助函数,用于简化在 Vue 组件中访问和使用 Vuex store 的过程。
如果我们不使用辅助函数,当我们在组件中需要使用 Vuex 的状态或触发 Vuex 的操作时,我们需要通过 this.$store
来访问。比如:
export default {
computed: {
count() {
return this.$store.state.count;
}
},
methods: {
increment() {
this.$store.commit('increment');
}
}
}
在上面的代码中,我们在计算属性 count
中直接访问了 Vuex 的状态 count
,并且在方法 increment
中触发了 Vuex 的 mutation increment
。
使用了辅助函数后:
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
computed: mapState(['count']),
methods: mapMutations(['increment'])
}
我们也可以使用展开运算符去映射多个:
computed: {
...mapState(['count', 'xxxx']),
anotherComputedProperty() {
// 你的代码
}
},
methods: {
...mapMutations(['increment', 'xxxxxx']),
anotherMethod() {
// 你的代码
}
}
接下来,我们通过面试中可能会问到的问题,来强化我们的理解和记忆:
1、什么是 Vuex?为什么我们需要它?
Vuex 是 Vue.js 的状态管理模式和库。在大型单页面应用中,我们需要一个集中式存储来管理多个组件的共享状态。通过 Vuex,我们可以更有效地跟踪状态的变化。
2、Vuex 的核心概念有哪些?
Vuex 的核心概念包括 state、getters、mutations、actions 和 modules。
State 提供了单一状态树,所有的状态都是响应式的。Getters 允许我们从 state 中派生出一些状态。Mutations 用于更改状态,且必须是同步函数。
Actions 类似于 mutations,但它可以包含任意异步操作。Modules 允许我们将 store 分割成模块,每个模块拥有自己的 state、mutation、action、getter,甚至可以嵌套子模块。
3、请解释一下 Vuex 的工作流程
a) 用户在界面中进行操作,触发 Store 中的 Action。
b) Action 内部调用对应的 Mutation 来修改 State。
c) State 的变化导致视图的更新。
4、什么是 mutation 和 action?他们有什么区别?
Mutation 是用于修改 Vuex Store 中 state 的方法。它必须是同步的。
Action 类似于 mutation,但它可以包含任意异步操作,然后在需要修改 state 时调用对应的 mutation。Action 是处理异步操作的地方,而 mutation 是更改状态的地方。
5、你怎么在组件中使用 Vuex 的 state 和 getters?
我们可以使用 Vuex 提供的 mapState
和 mapGetters
辅助函数将 store 中的 state 和 getters 映射到局部计算属性。例如:
import { mapState, mapGetters } from 'vuex'
export default {
computed: {
...mapState(['stateItem']),
...mapGetters(['getterItem'])
}
}
转载自:https://juejin.cn/post/7234680624657023031