Vuex
基本认识
- Vuex是专为Vue.js应用程序开发的状态管理模式
- 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生改变
- Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能
- 使用场景:状态在多个组件间共享时
- 登录状态、用户名、头像、地理位置等
- 商品的收藏、购物车中的物品等
基本使用
-
第一步:安装Vuex
npm install vuex --save
-
第二步:一般我们是在src文件夹下面创建一个store文件夹,并在在store文件夹下面创建index.js文件
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { counter: 1000 }, mutations: { // 方法 increment(state){ state.counter++ }, decrement(state){ state.counter-- }, }, actions: { }, getters: { }, modules: { } }) export default store
-
第三步:在Vue实例中挂载store对象
import Vue from 'vue' import App from './App' import store from "./store"; Vue.config.productionTip = false new Vue({ el: '#app', store, render: h => h(App) })
-
第四步:在组件中使用通过
{{$store.state.参数名}}
-
第五步:修改counter的值,在组件中使用
this.$store.commit('increment')
即可调用store中的increment方法methods: { addition() { this.$store.commit('increment') }, subtraction() { this.$store.commit('decrement') } }
State
单一状态树
用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
Getter
类似组件的计算属性
- 应用场景:有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
Mutation
-
应用场景:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
-
基本使用:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变更状态 state.count++ } } })
store.commit('increment')
-
提交载荷(Payload)
你可以向
store.commit
传入额外的参数,即 mutation 的 载荷(payload):// ... mutations: { increment (state, n) { state.count += n } }
store.commit('increment', 10)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
// ... mutations: { increment (state, payload) { state.count += payload.amount } }
store.commit('increment', { amount: 10 })
-
https://vuex.vuejs.org/zh/guide/mutations.html
Action
Action 类似于 mutation,不同在于:
-
Action 提交的是 mutation,而不是直接变更状态。
-
Action 可以包含任意异步操作。
-
https://vuex.vuejs.org/zh/guide/actions.html
-
分发Action:Action 通过
store.dispatch
方法触发store.dispatch('increment')
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
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 的状态
store.state.b // -> moduleB 的状态
- https://vuex.vuejs.org/zh/guide/modules.html
项目结构
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
- 应用层级的状态应该集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块