vuex
什么是vuex
Vuex是专门为vue.js应用程序开发的状态管理模式+库。在Vue中实现集中管理数据的一个Vue插件,对Vue中多个组件的共享状态进行集中式管理。也属于一种组件间的通信方式,且适用于任意组件间通信。
状态自管理应用包含的部分:
- 状态,驱动应用的数据源
- 视图,以声明方式将状态映射到视图
- 操作,响应在视图上的用户输入导致的状态变化
单项数据流理念:
因此我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。
使用场景:
- 多个组件依赖同一个状态时
- 来自不同组件的行为需要变更同一个状态的时候。
**Vuex思想:**通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
搭建vuex环境
创建文件:src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
在main.js
中创建vm时传入store
配置项
......
//引入store
import store from './store'
......
//创建vm
new Vue({
el:'#app',
render: h => h(App),
store
})
vuex – State
属性介绍
state
属性是vuex中用于存放组件之间共享的数据。通常将一些组件之间共享的状态主要存放在state
属性中。
vuex使用单一状态树,用一个对象就包含了全部的应用层级状态。这意味着每个应用仅仅包含一个store实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
state的使用
这里基于登录的业务逻辑,实现一个vuex
集中管理token
值,以便于发送请求时获取token值携带在header中的业务。
在src/store/index.js
中:
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {
token:'',
userMessage:{},
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
此时,我们在state
中存放了两个变量:token
、userMessage
。
当我们在其他组件中需要获取该变量时,使用this.$store.state.变量名获取
this.$store.state.token;
this.$store.state.userMessage;
当我们需要响应式获取vuex
中存储的状态时,最简单的方式是使用计算属性。
如果存放在data
中,则不能响应式展示vuex
中的数据,因为data
中的内容只会在created
钩子函数触发前初始化一次。而 computed则是通过【依赖追踪】实现的,在 computed 求值时引用的 Vue 变量变化时,会触发对 computed 的重新计算。所以我们可以使用computed 去引用 Vuex 状态变量,从而使得依赖追踪生效。
vuex – Mutations
更改vuex的store中的状态的唯一方式是提交mutation
。(不能直接操作state
修改数据)。
Vuex中的mutation
非常类似于事件:每个 mutation
都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
}
//准备mutations对象——修改state中的数据
const mutations = {
set_token(state,token){
state.token = token;
localStorage.token = token;
},
del_token(state){
state.token = '';
localStorage.removeItem('token');
}
}
//准备state对象——保存具体的数据
const state = {
token:'',
userMessage:{},
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
此时,我们在mutations
对象中定义了两个函数:set_token
和del_token
,实现了将token存入本地存储和移出本地存储的功能。
提交的方式:使用this.$store.commit('方法名',参数)
this.$store.commit('set_token',token);
this.$store.commit('del_token');
此时,我们就实现了使用提交mutation
的方法更改Vuex中的store
状态。
vuex – Action
Action
类似于mutation
,与mutation
的区别在于:
- Action提交的是mutaion,而不是直接变更状态
- Action可以包含任意异步的操作
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
set_token(context){
context.commit(set_token)
},
del_token(context){
context.commit(del_token)
}
}
//准备mutations对象——修改state中的数据
const mutations = {
set_token(state,token){
state.token = token;
localStorage.token = token;
},
del_token(state){
state.token = '';
localStorage.removeItem('token');
}
}
//准备state对象——保存具体的数据
const state = {
token:'',
userMessage:{},
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
分发Action
Action
通过store.dispatch
方法触发:
this.$store.dispatch('set_token');
this.$store.dispatch('del_token');
Action的优势在于不会像使用mutation必须同步执行,在action内部可以执行异步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('set_token')
}, 1000)
}
}
// 以载荷形式分发
this.$store.dispatch('incrementAsync',{amount:10})
// 以对象形式分发
this.$store.dispatch({
type: 'incrementAsync',
amount: 10
})
vuex–getters
使用场景
当需要对state
中的数据进行二次加工,从state
中派生出一些状态时会使用到。
getters
接受state
作为其第一个参数:
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
token:'',
userMessage:[
{id:1,text:'111',done:true},
{id:2,text:'222',done:true},
],
},
//抽取state中的状态
getters:{
doneTod(state){
return state.userMessage.filter(todo => todo.done);
}
}
//准备mutations对象——修改state中的数据
const mutations = {
set_token(state,token){
state.token = token;
localStorage.token = token;
},
del_token(state){
state.token = '';
localStorage.removeItem('token');
}
}
//准备state对象——保存具体的数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
此时定义的getters
方法实现了从state.userMessage
中抽取了done
属性的操作。
通过属性访问
Getter会暴露为store.getters
对象,可以以属性的形式访问:
this.$store.getters.doneTods
Getter 也可以接受其他 getter 作为第二个参数:
doneTodosCount (state, getters) {
return getters.doneTodos.length
}
通过方法访问
可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
this.$store.getters.doneTod()
辅助函数的使用
mapState
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性。
import {mapState} from 'vuex'
computed: mapState({
//箭头函数
token: state => state.token,
userMessage(state) {
state.userMessage
}
})
当映射的计算属性的名称与state
的子节点名称相同时,也可以给mapState
传一个字符串数组。
computed: mapState(['token']);
对象展开运算符
mapState
函数返回的是一个对象。通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed
属性。但是自从有了对象展开运算符后,我们可以极大地简化写法:
//对象写法
computed:{
localComputed(){
...mapState({
token:'token',
userMessage:'userMessage'
})
}
}
//数组写法
computed:{
localComputed(){
...mapState(['token','userMessage'])
}
}
mapGetters
mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
import { mapGetters } from 'vuex'
//数组写法
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTod'
// ...
])
}
}
//对象写法
...mapGetters(doneTod:'doneTod')
mapActions方法
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用 mapActions
辅助函数将组件的 methods 映射为 store.dispatch
调用(需要先在根节点注入 store
):
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'set_token', //
// `mapActions` 也支持载荷:
'del_tooken' //
]),
...mapActions({
setToken: 'set_token' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
mapMutations方法
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
调用(需要在根节点注入 store
)。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'set_token', // 将 `this.set_token()` 映射为 `this.$store.commit('set_token')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
del: 'del_token' // 将 `this.del()` 映射为 `this.$store.commit('del_token')`
})
}
}
tions } from ‘vuex’
export default {
// …
methods: {
…mapMutations([
‘set_token’, // 将 this.set_token()
映射为 this.$store.commit('set_token')
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
del: 'del_token' // 将 `this.del()` 映射为 `this.$store.commit('del_token')`
})
}
}