vuex是什么?
用官方的话来说,Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
vuex是基于vue框架的一个状态管理库。可以管理复杂应用的数据状态,比如兄弟组件的通信、多层嵌套的组件的传值等等。
vuex有5个核心概念——State、Getter、Mutation、Action、Module。
- state(全局变量)
- mutations(修改全局变量的方法)
- actions(用于提交mutations的方法)
- getters(其他vue组件读取state变量的中间变量,作者理解,该处相当于导出了state)
- Modules(面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules))
什么时候用?
- 传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
- 我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
怎么用?
第一步
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
Vue.use(Vuex) // 使用插件
// 导出store实例
export default new Vuex.Store({
state: {
},
mutations,
actions
//mutations 也可以不单独引入,使用下面这种写法
// mutations: {
//}
})
第二步
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 重点在这里-----增加store属性,值是导出store的实例
components: { App },
template: '<App/>'
})
通过上面两个步骤,每个组件中都有了 s t o r e 属 性 , 就 是 我 们 创 建 的 容 器 。 里 面 有 c o m m i t , d i s p a t c h , s t a t e , g e t t e r s , a c t i o n s , m u t a t i o n s , 在 每 个 组 件 中 可 以 通 过 t h i s . store属性,就是我们创建的容器。里面有commit,dispatch,state,getters,actions,mutations,在每个组件中可以通过this. store属性,就是我们创建的容器。里面有commit,dispatch,state,getters,actions,mutations,在每个组件中可以通过this.store打印出来看看。
开始使用
在store.js中定义状态
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
Vue.use(Vuex) // 使用插件
export default new Vuex.Store({
state: {
count: 1 // state中定义响应式的数据
},
mutations,
actions
})
使用状态:在store的state中定义的状态count,在组件中可以使用this.$store.state.count获取。
定义mutations
mutations.js
const mutations= {
add (state, num) {
state.count = state.count + num
}
}
export default mutations
提交mutations
在组件中通过commit提交mutations去修改state中的状态
this.$store.commit('add', 1)
定义actions
在actions.js中添加对应的方法
const actions = {
add2({commit}, num) {
// 第一个参数是store实例,第二个是传入的参数
setTimeout(() => {
commit('add', num)
}, 1000)
}
}
export default actions
派发动作
组件中可以使用dispatch派发一个动作,来触发actions中的方法,actions可以异步的提交mutations去修改state中的状态
this.$store.dispatch('minusTen', 10)
actions主要是复用,封装代码,处理异步,请求接口等等,真正修改状态放到了mutations中处理
定义getters
在store的getters中添加对应的方法
export default new Vuex.Store({
state: {
count: 1,
person: {
name: '张三'
}
},
getters: {
getName (state) {
// getters是同步的
return state.person.name
}
}
})
使用getters
this.$store.getters.getName
getters定义的方法相当于计算属性,相当于定义在computed一样,有缓存,依赖改变会重新计算。
组件代码演示
<template>
<div class="hello">
<h1>{{ this.$store.state.count }}</h1>
<h1>{{ this.$store.getters.getName }}</h1>
<button @click="syncAdd">同步加1</button>
<button @click="asyncAdd">异步加1</button>
</div>
</template>
<script>
export default {
methods: {
syncAdd () {
this.$store.commit('add', 1)
},
asyncAdd () {
this.$store.dispatch('add2',1)
}
}
}
</script>
简写
上面的写法都是在this.$store中获取属性或方法进行操作。
this.$store.state.count
this.$store.getters.getName
this.$store.commit('add', 1)
this.$store.dispatch('add2')
但是这些操作写起来比较繁琐,每次都要写this.$store,为了简写,所以vuex提供了一些映射的方法,直接导入到组件中就可以使用了。
<template>
<div class="hello">
<h1>{{ count }}</h1>
<h1>{{ getName }}</h1>
<button @click="syncAdd">同步加10</button>
<button @click="asyncAdd">异步加10</button>
</div>
</template>
<script>
import {mapActions, mapState, mapMutations, mapGetters} from 'vuex'
export default {
computed: {
...mapState(['count']),
...mapGetters(['getName'])
},
methods: {
syncAdd () {
this.add(1)
},
asyncAdd () {
this.add2(1)
},
...mapActions(['add2']),
...mapMutations(['add'])
}
}
</script>
有一点需要说明的是,使用扩展运算符,表示这些方法返回的都是对象,mapState和mapGetters需要定义在计算属性中,因为他们定义的数据是响应式的。而mapActions和mapMutations需要定义在methods中。
拆分模块Modules
状态是可以分层的,当一个项目维护的状态太多,可以拆分成单独的模块,在定义store中有个modules属性,里面可以定义单独的模块。
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
'page1': {
namespaced: true,
state: {
count: 1,
person: {
name: '张三'
}
},
mutations: {
add(state, num) {
state.count = state.count + num
}
},
actions: {
add2({commit}) {
setTimeout(() => {
commit('add', 1)
}, 1000)
}
},
getters: {
getName (state) {
return state.person.name
}
}
}
}
})
在组件中这样用
<template>
<div class="hello">
<h1>{{ count }}</h1>
<h1>{{ getName }}</h1>
<button @click="syncAdd">同步加10</button>
<button @click="asyncAdd">异步加10</button>
</div>
</template>
<script>
import {mapActions, mapState, mapMutations, mapGetters} from 'vuex'
export default {
computed: {
...mapState('page1', ['count']),
...mapGetters('page1', ['getName'])
},
methods: {
syncAdd () {
this.add(10)
},
asyncAdd () {
this.add2(10)
},
...mapActions('page1', ['add2']),
...mapMutations('page1', ['add'])
}
}
</script>
每个方法都传了两个参数,第一个参数指定命名空间,第二个参数是对应的属性,为了进一步简写,可以通过帮助函数指定命名空间,指定当前组件在使用的模块。
<template>
<div class="hello">
<h1>{{ count }}</h1>
<h1>{{ getName }}</h1>
<button @click="syncAdd">同步加10</button>
<button @click="asyncAdd">异步加10</button>
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
// 创建帮助函数指定命令空间
let { mapActions, mapState, mapMutations, mapGetters } = createNamespacedHelpers('page1')
export default {
computed: {
...mapState(['count']),
...mapGetters(['getName'])
},
methods: {
syncAdd () {
this.addTen(10)
},
asyncAdd () {
this.minusTen(10)
},
...mapActions(['add2']),
...mapMutations(['add'])
}
}
</script>
不使用简写
this.$store.getters['page1/getName']
this.$store.state.page1.count
this.$store.commit('page1/add', 1)
this.$store.dispatch('page1/add2', 1)