VUEX
VUEX 基础
-
Vuex 应用开发的状态管理模式。采用集中式存储管理应用的所有组件的状态。
-
Vuex 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
-
Vuex解决了什么问题?
- 多个组件依赖于同一状态时,多层嵌套组件和兄弟组件状态传参问题。
- 来自不同组件的行为需要变更同一状态问题。以往采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
-
什么时候使用 Vuex?
- 多个组件依赖于同一状态时。
- 来自不同组件的行为需要变更同一状态。
-
核心属性:
-
State 状态: 存储状态数据,状态存储是响应式的。
- 获取 state 数据:
this.$store.state
获取, store 实例中读取状态最简单的方法就是在计算属性 (opens new window)中返回某个状态 。 - 获取多个状态:
mapState
辅助函数。mapState
返回的是一个对象,使用对象展开运算符...
将对象混入到外部对象中。
- 获取 state 数据:
-
**Getter: ** 用于获取
state
。- 参数:Getter 接受 state 作为其第一个参数,其他 getter 作为第二个参数。
- 返回值:返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
- 获取单个 getters:
this.$store.getters
对象。 - 获取多个 getters:
mapGetters
辅助函数,返回多个 getters 对象。
-
**Mutation: ** 提交 mutation 是更改状态的唯一方法。
-
规则:
- mutation 必须是同步函数(在回调函数中进行的状态的改变都是不可追踪)
- 使用常量替代 mutation 事件类型
- 在组件中使用
this.$store.commit('xxx')
提交 mutation,或者使用mapMutations
辅助函。
-
定义和提交:
//定义:第一个参数 state,第二个参数提交数据 mutations: { increment (state, payload) { state.count += payload.amount } } //提交:第一个参数 mutation 事件类型,第二个参数为提交数据 store.commit('increment', { amount: 10 }) //对象风格提交 store.commit({ type: 'increment', amount: 10 })
-
实现: 从 _mutations 中取出对应的 mutation,循环执行其中的每一个 mutation。
commit (type, payload, _options) { //_mutations 为用户定义的 mutation 的数组,type 为 namespace + path 拼接字符串 const entry = this._mutations[type]; entry.forEach(function commitIterator (handler) { handler(payload); }); }
-
-
Action:一般用于调用异步 API 和分发多重 mutation
-
Action 提交的是 mutation,而不是直接变更状态。
-
Action 可以包含任意异步操作。
-
使用:使用
this.$store.dispatch('xxx')
分发 action,或者使用mapActions
辅助函数将组件的 methods 映射为store.dispatch
调用(需要先在根节点注入store
) -
store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise,并且store.dispatch
仍旧返回 Promise,然后 then 提交 commit 修改 state。 -
多次提交同一个action: mapActions辅助函数。
-
//定义 actions: { checkout ({ commit, state }, products) { // 把当前购物车的物品备份起来 const savedCartItems = [...state.cart.added] // 发出结账请求,然后乐观地清空购物车 commit(types.CHECKOUT_REQUEST) // 购物 API 接受一个成功回调和一个失败回调 shop.buyProducts( products, // 成功操作 () => commit(types.CHECKOUT_SUCCESS), // 失败操作 () => commit(types.CHECKOUT_FAILURE, savedCartItems) ) } } //使用 promise store.dispatch('checkout').then((res) => { commit('checkout', res.data) }) // 使用 async await actions: { async actionA ({ commit }) { commit('checkout', await getData()) } }
-
实现:取出 _actions 中的所有对应 action,将其执行,如果有多个则用 Promise.all 进行包装。
dispatch (type, payload) { //_actions 为用户定义的 action 的数组,type 为 namespace + path 拼接字符串 const entry = this._actions[type]; return entry.length > 1 ? Promise.all(entry.map(handler => handler(payload))) : entry[0](payload); }
-
-
Module:
- 产生:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,
store
对象就有可能变得相当臃肿。 - 作用:将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、嵌套子模块。
- 数据结构:模块的设计就是一个树型结构,
store
本身可以理解为一个root module
,它下面的modules
就是子模块 - 命名空间:
- 全局命名空间:默认情况为全局命名空间,多个模块能够对同一
mutation
或action
作出响应。 - 局部命名空间:
namespaced: true
的方式使其成为带命名空间的模块,所有getter
、action
及mutation
都会自动根据模块注册的路径调整命名。
- 全局命名空间:默认情况为全局命名空间,多个模块能够对同一
- 产生:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,
-
-
规则:
- 应用层级的状态应该集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑都应该封装到 action 里面。
-
流程:
-
页面组件 dispatch 分发 action 获取数据;
-
Action 中异步获取数据,获取后 commit 同步提交 mutation;
-
mutation 同步修改 state 状态,state 通过 getters 通知变化;
-
在组件的计算属性中,通过 getters 来动态获取 state 中的值。
-
Vuex 缺点:
- vuex中存储的数据不能持久化。vuex 的 store 中的数据是保存在运行内存中的,当页面刷新后,页面会重新加载 vue 实例,vuex 里面的数据就会被重新赋值,这样就会出现页面刷新vuex中的数据丢失的问题。需要监听处理来维持vuex存储的数据状态持久化。
-