—— Vuex 的使用 ——
直接用途:多个组件共享状态
Vuex 官网:Vuex 是什么? | Vuex (vuejs.org)
1. state - 单一状态树
-
官方解释
Vuex 通过 Vue 的插件系统将 store 实例从根组件中“注入”到所有的子组件里。且子组件能通过
this.$store
访问到。类似
data
属性
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 创建一个 store
const store = new Vuex.Store({
// 1. 这样就给store里添加了一个 address 对象 这里写死了 以后用是外界传入的
state: {
address: {
provinceName:"陕西省",
cityName:"西安市",
detailInfo:"xxx"
}
}
})
export default store
2. Getters - 计算属性
-
官方解释
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行
过滤
并计数
,这里我们计算
完整的地址Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的
计算属性
)。类似
computed
属性
getters:{
// 这里就动态计算了详细地址 '陕西省西安市xxx'
addstr(state) {
return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
}
}
3. Mutations - 同步提交
- 官方解释
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)**和一个**回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
-
提交载荷(Payload)
你可以向
store.commit
传入额外的参数
即 mutation 的载荷(payload)在大多数情况下,载荷应该是一个
对象
,这样可以包含多个字段并且记录的 mutation 会更易读这里
address
就是载荷
mutations:{
// 更新收货地址 外界传入一个 地址对象 更新当前 state 中的对象
updateAddress(state, address){
state.address = address
// 多个方法下 这样调用
this.commit('saveAddressToStroage')
},
saveAddressToStroage(state){
uni.setStorageSync('address',JSON.stringify(state.address))
}
}
诶,有人就要问了,我写的异步提交方法怎么不生效啊?这里我们需要使用action
- 使用常量替代 Mutation 事件类型
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import { createStore } from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = createStore({
state: { ... },
mutations: {
// 我们可以使用 ES2015 风格的计算属性命名功能
// 来使用一个常量作为函数名
[SOME_MUTATION] (state) {
// 修改 state
}
}
})
用不用常量取决于你——在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。
4. Action - 异步提交
- 官方解释
Action 类似于 mutation,不同在于:
1. `Action `提交的是 `mutation`,而不是直接变更状态`state`。
2. `Action `可以包含任意**异步操作**。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了
-
提交载荷(Payload)
异步提交和前面一样 传入的载荷一般是个对象
mutations:{
// 更新收货地址 外界传入一个 地址 更新当前state 中的对象
updateAddress(state, address){
state.address = address
// 多个方法下 这样调用
this.commit('saveAddressToStroage')
},
saveAddressToStroage(state){
uni.setStorageSync('address',JSON.stringify(state.address))
}
}
// 在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读
actions: {
updateAddressSync(context, payload){
context.commit('updateAddress', payload)
}
}
Action 通过 store.dispatch
方法触发:
// 以载荷形式分发
store.dispatch('updateAddressSync', address) //address 是个对象
// 以对象形式分发
store.dispatch({
type: 'updateAddressSync',
address: {
...
}
})
5. Modules - 模块化
为什么要使用模块化?
-
官方解释
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
可以全部写在 store.js 中
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 的状态
也可以用导入的方式
- store.js
import Vue from 'vue'
import Vuex from 'vuex'
// 1. 导入user 的 vuex 模块
import moduleUser from './user.js'
Vue.use(Vuex)
const store = new Vuex.Store({
// TODO:挂载 store 模块
modules: {
// 2. 挂载 user 的 vuex 模块,模块内成员的访问路径被调整为 m_user,例如:
'm_user': moduleUser
},
})
export default store
- 创建
user.js
export default {
// 开启命名空间
namespaced: true,
// 数据节点
state:() =>({
// 在本地中拿到信息 若没有 就是空对象
address:JSON.parse(uni.getStorageSync('address') || '{}')
}),
// 方法
mutations:{
// 更新收货地址
updateAddress(state, address){
state.address = address
// 使用 this.commit 调用方法存储信息到本地
this.commit('m_user/saveAddressToStroage')
},
// 持久化存储address
saveAddressToStroage(state){
uni.setStorageSync('address',JSON.stringify(state.address))
}
},
getters:{
// 计算地址
addstr(state) {
if (!state.address.provinceName) return ''
return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
}
}
}
- 在页面中配置
<script>
// 1. 按需导入辅助函数
import {
mapState,
mapMutations,
mapGetters
} from 'vuex'
export default {
data() {
return {
// 2. 注释掉 address 对象 使用 m_user 中 address 的对象
// address: {}
};
},
computed: {
// 3. 把 m_user 模块中的 address 对象映射到当前组件中使用, 代替 data 中 address 对象
...mapState('m_user',['address']),
addstr() {
if (!this.address.provinceName) return ''
return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
}
},
methods: {
// 4. 把 m_user 模块中的 updateAddress 函数映射到当前组件中
...mapMutations('m_user',['updateAddress']),
// 5. 把 m_user 模块中的 addstr getters方法映射到组件中
...mapGetters('m_user',['addstr'])
},
}
</script>
—— 总结 ——
仅是个人理解,更多更详细的内容还得看Vuex 官网:Vuex 是什么? | Vuex (vuejs.org),若有错误请指出!