Vuex状态管理模式
2021-06-16 本文已影响0人
gitJason
Vuex是什么?
Vuex是一个专为Vue.js应用程序开发的状态管理模式
Vuex是全局的状态管理
Vuex用来做什么?
Vuex用于组件之间的传值,多个组件共享数据
Vuex的数据是响应式的,当我们在A组件更新了某个状态,来到B组件,B组件会动态更新
State
State
用来存储状态
在组件中获取Vuex
状态
由于Vuex
的状态存储是响应式的,从store
实例中读取状态最简单的方法就是在计算属性
中返回某个状态:
computed: {
count: () => store.state.count
// or 将状态从根组件“注入”到每一个子组件中 Vue.use(Vuex)
count: () => this.$store.state.count
},
mapState 获取方式
import { mapState } form 'vuex'
computed: {
...mapState({
// 1. 基础用法 store/index.js
isLogin: (state) => state.isLogin
// 2. 使用模块 store/modules/user.js
isLogin: (state) => state.user.isLogin
}),
},
Getters
Getters
类似计算属性,只有当它的依赖发生改时才会重新求值
Getter 接受 state 作为其第一个参数:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
在组件中使用
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
mapGetters 获取方式
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
// 使用Modules store/user.js
...mapGetters('user',[
'increment',
'incrementBy',
// ...
])
}
}
Mutations
更改store
中状态的唯一方法是mutations
mutations
第一个参数是state
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
调用方法
store.commit('increment')
你可以向store.commit
传入额外的参数
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 10)
记住 Mutation 必须是同步函数
在组件中提交 Mutation
computed: {
doneTodosCount () {
return this.$store.commit('increment')
}
}
mapMutations 方式提交
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapMutations([
'increment',
'incrementBy',
// ...
])
// 使用Modules store/user.js
...mapMutations('user',[
'increment',
'incrementBy',
// ...
])
}
}
Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
注册一个简单的 action:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用context.commit
提交一个 mutation,或者通过context.state
和context.getters
来获取 state 和 getters。
实践中,我们会经常用到 ES2015 的 参数解构 (opens new window)来简化代码
actions: {
increment ({ commit }) {
commit('increment')
}
}
在组件中触发 Action
methods: {
increment () {
this.$store.dispatch('increment')
}
}
mapActions 方式触发
import { mapActions } from 'vuex'
export default {
// ...
methods: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapActions([
'increment',
'incrementBy',
// ...
])
// 使用Modules store/user.js
...mapActions('user',[
'increment',
'incrementBy',
// ...
])
}
}
组合 Action
有时候需要组合多个action
,例如有时候需要在actionB中调用actionA
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
利用 async / await ,我们可以如下组合 action:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
// ...
}
}
Modules
当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
modules 将 store 分割成模块。
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
moduleA,
moduleB
}
})
项目使用案例
@/store/modules/user.js :
export default {
namespaced: true,
state: {
// 存储状态
isLogin: false
},
mutations: {
// 修改状态
SET_ISLOGIN(state, val) {
state.isLogin = val
}
},
actions: {
// 异步操作
login({ commit }, query) {
api.login({
code: query.code,
iv: query.iv
}).then(res => {
commit('SET_ISLOGIN', true)
})
}
}
}
@/store/index.js :
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
// 安装 Vuex
Vue.use(Vuex)
// 创建一个 store
export default new Vuex.Store({
modules: {
user,
// ...
}
})
@/main.js :
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from '@/store';
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app');