1.描述
2.基本操作
3.vuex对象实例
4.state
5.Getters
6.mutions
7.actions
8.modules
为什么要用vuex呢?
1.数据跨组件共享
2.防止数据意外修改
3.调试、测试
4.全局、统一、单一
Vuex
是一个专为 Vue.js 应用程序开发的状态管理模式。
每一个 Vuex
应用的核心就是 store
(仓库)。“store
”基本上就是一个容器,它包含着你的应用中大部分的状态 (state
)。Vuex
和单纯的全局对象有以下两点不同:
-
Vuex
的状态存储是响应式的。当Vue
组件从store
中读取状态的时候,若store
中的状态发生变化,那么相应的组件也会相应地得到高效更新。 -
你不能直接改变
store
中的状态。改变store
中的状态的唯一途径就是显式地提交 (commit
)mutation
。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
注意!改变 store
中的状态的唯一途径就是显式地提交 (commit
) mutation
注意!改变 store
中的状态的唯一途径就是显式地提交 (commit
) mutation
注意!改变 store
中的状态的唯一途径就是显式地提交 (commit
) mutation
基本操作
- npm install vuex -S (下载)
- 创建vuex对象实例
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
- 挂载到vue上
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
这是vuex最基础的结构,下面我们就了解一下vuex的相关配置。
vuex对象实例
// strict:true, //严格模式 防止代码直接修改state (strict开发阶段可以为true,但打包的时候一定要为false 或者不写)
state:{},
mutations:{},
actions:{},
getters:{},
modules:{}
state
state是存放所有状态的对象,在vue组件中可以通过this.$store.state.xxx
来获取相应的状态值。
export default new Vuex.Store({
state:{
count:10
}
})
// 创建一个 Counter 组件
const Counter = {
template: `<div>{{ count }}</div>`, //10
computed: {
count () {
return store.state.count
}
}
}
由于 Vuex
的状态存储是响应式的,从 store
实例中读取状态最简单的方法就是在计算属性中返回某个状态。
mapState 辅助函数
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed:{
...mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
}
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
computed: {
mapState([
// 映射 this.count 为 store.state.count
'count'
])
}
Getter
有时候我们需要从 store 中的 state 中派生出一些状态,相当于计算属性,这时候我们就可以用到Getter:
原先
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
现在
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: {
doneTodos() {
return this.$store.getters.doneTodos
}
}
Getter接受两个参数
- state
- 用到的参数
Getter
只是对state
里的属性进一步的处理,理论上不会再Getter
里面来改变state
中的值,所有的改变都需要在mutation
中进行,Getter
相当于组件中的计算属性。
mapGetters 辅助函数
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
如果你想将一个 getter 属性另取一个名字,使用对象形式:
mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
Mutation
更改 Vuex
的 store
中的状态的唯一方法是提交 mutation
。Vuex
中的 mutation
非常类似于事件:每个 mutation
都有一个字符串的 事件类型 (type
) 和 一个 回调函数 (handler
)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state
作为第一个参数:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state,n) {
// 变更状态
state.count+=n
}
}
})
你不能直接调用一个 mutation handler
。这个选项更像是事件注册:“当触发一个类型为 increment
的 mutation
时,调用此函数。”要唤醒一个 mutation handler
,你需要以相应的 type
调用 store.commit
方法:
store.commit('increment',10)
mutations 接受两个参数
- state
- 传递的参数(多个参数可以通过一个对象的形式传递)
Mutation 必须是同步函数,处理异步请求我们可以使用Action
mapMutations辅助函数
组件中提交 mutation有两种形式:
- this.$store.commit(‘xxx’)
- mapMutations 辅助函数
export default {
// ...
methods: {
useMutation(){
this.$store.commit('increment',10);
}
}
}
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
},
//第二种写法 对象扩展 context.commit
increment ({commit}) {
context.commit('increment')
}
}
})
Action
函数接受一个与 store
实例具有相同方法和属性的 context
对象.
因此你可以调用 context.commit
提交一个 mutation
,或者通过 context.state
和 context.getters
来获取 state
和 getters
。
分发 Action
Action 通过 store.dispatch 方法触发:
store.dispatch('increment')
乍一眼看上去感觉多此一举,我们直接分发 mutation
岂不更方便?实际上并非如此,还记得 mutation
必须同步执行这个限制么?Action
就不受约束!我们可以在 action
内部执行异步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
actions可以处理多个异步请求 通过.then来执行。
store.dispatch('actionA').then(() => {
// ...
})
如果我们利用 async / await,我们可以如下组合 action:
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
组件中使用
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
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 的状态
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
同样,对于模块内部的 action
,局部状态通过 context.state
暴露出来,根节点状态则为 context.rootState
:
rootState rootState rootState
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}