Vuex使用小结

什么是状态管理模式?

在了解Vuex之前,我们需要先了解什么是状态管理模式

在一些大型应用中,有时我们会遇到单页面中包含着大量的组件及复杂的数据结构,而且可能各组件还会互相影响各自的状态,在这种情况下组件树中的事件流会很快变得非常复杂,也使调试变得异常困难。

为了解决这种情况,所以我们引入状态管理这种设计模式,来降低这种情况下事件的复杂程度并且使调试变得可以追踪。

那么什么是状态管理模式呢?

状态管理模式的核心思想就是,将各个组件的共享状态(这里所谓的状态,其实就是组件的一些数据)抽取取出,使用一个全局的单例的对象来进行管理,从而简化程序结构,且易于维护。

用大白话来说就是,将系统中的一些经常需要用到的全局变量,集中起来用一个组件统一管理,其他要使用这些数据的组件,获取或修改这些数据都需要同这个统一管理的组件交互,从而保证这些数据只有一份,当其被修改时,所有组件都可以感知到,结合响应式数据流,可以实时更新所有页面上的数据。

什么是Vuex?Vuex能做什么?

概述

这是Vuex官网的描述:

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式组件。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

看起来有点懵逼~

其实只要理解到上面大白话说的状态管理模式的意思,就能明白他在说什么。说白了Vuex就是上面提到的那个统一管理全局数据的组件,配合Vue的响应式数据流,可以实时变更所有页面上的数据。

原理

下图是Vue官方提供的Vuex原理图:

在这里插入图片描述

原理图解析

这个图描述了Vuex工作时的流程,下面举例分步骤详细地解释下:

  1. 举例A组件需要修改用户信息(用户信息是一个全局数据,即图中的状态),于是A组件去调用修改用户信息的Action,Action实际就是一个函数;
  2. 修改用户信息的Action被调用,于是去请求后台服务,发起修改用户信息请求,后台若响应失败,则修改失败,流程停止,若响应成功,则派发调用为用户信息这个状态数据赋值的Mutation;
  3. Mutation其实就是负责实际修改全局数据的函数,通常也只负责修改下State,不会有其它逻辑;
  4. 用户信息的State,这个全局数据被Mutation修改了,于是所有使用了用户信息的组件,它们视图上的用户信息数据都会实时更新,至此,就完成了一次状态管理。

为什么要区分Action与Mutation?

看了上面的示意图以及解析,可能会产生一个疑问,为什么我们不直接在Action中修改全局数据呢,而要画蛇添足似的弄个Mutation?

这是关于这个问题,Vue的作者在知乎给出的回答:

中文翻译可能有些偏差(不是我翻的)。区分 actions 和 mutations 并不是为了解决竞态问题,而是为了能用 devtools 追踪状态变化。

事实上在 vuex 里面 actions 只是一个架构性的概念,并不是必须的,说到底只是一个函数,你在里面想干嘛都可以,只要最后触发 mutation 就行。异步竞态怎么处理那是用户自己的事情。vuex 真正限制你的只有 mutation 必须是同步的这一点(在 redux 里面就好像 reducer 必须同步返回下一个状态一样)。

同步的意义在于这样每一个 mutation 执行完成后都可以对应到一个新的状态(和 reducer 一样),这样 devtools 就可以打个 snapshot 存下来,然后就可以随便 time-travel 了。

如果你开着 devtool 调用一个异步的 action,你可以清楚地看到它所调用的 mutation 是何时被记录下来的,并且可以立刻查看它们对应的状态。其实我有个点子一直没时间做,那就是把记录下来的 mutations 做成类似 rx-marble 那样的时间线图,对于理解应用的异步状态变化很有帮助。

作者:尤雨溪
链接:https://www.zhihu.com/question/48759748/answer/112823337
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结一下:

  1. 区分Action和Mutation是为了devtools服务,从原理图中也能看到Mutation是和开发工具交互的,所以这并不是设计模式所需要的,不必过分纠结;
  2. 异步操作应该放在Action中,Mutation中只应该有同步操作,实际使用中,我们的Mutation通常只有修改State的简单逻辑;

Vuex的核心概念

Store(仓库)

Vuex程序会通过new Vuex.Store初始化一个Store,Vuex所有的操作都是围绕着Store来的,Store就是Vuex的一个根对象。

State(状态)

State就是我们前面提到的组件的状态,其实就是一些全局数据,现在我们把这些数据统一管理在State中,方便所有组件获取使用,并且可以响应式地更新。

Store对象是根对象,所以State数据会存放在Store中。

Mutation(变更)

Mutation函数负责实际修改State中的状态数据,直接操作State中的数据值。

Action(动作)

在Vuex中我们不会直接操作State中的值,这样会容易导致混乱,我们需要通过Action函数来调用对应的Mutation函数,然后由Mutation来实际负责修改State中的数据。

在Action函数中,你也可以通过Ajax从后端或其它的一些渠道来获取需要更新的数据。

Getters

Vuex 2.0中将Getters引入了Store中,如同Java中的get函数,我们可以通过Getters获取一些全局性的数据。

通常是当我们需要对数据进行一些逻辑处理时才使用getter,类似于计算属性computed,只不过getter是针对State的,如果没有这种需求,可以不使用getter。

Modules

Vue 2.0中对State进行了模块化处理,即每个模块都可以有各自的State,最终通过modules聚合在一起,方便管理维护。

Vuex的简单应用实例

示例代码目录结构

src

----support

--------vuex

------------modules

----------------user.js

------------getters.js

------------index.js

user.js

user模块的状态管理代码,可以存在多个这种模块

const user = {
    // 这就是我需要全局共享的数据
    state: {
        name: '',
        age: '',
        school: ''
    },

    // Mutation中仅有简单的赋值逻辑
    mutations: {
        SET_USER: (state, user) => {
            state.name = user.name
            state.age = user.age
            state.school = user.school
        },
    },

    // 我们在Action中修改用户数据,修改成功后,更新全局数据
    actions: {
        changeUser({
            // 这里可以拿到commit与state,commit用来分发到mutation,state即上面的state对象,可以拿到里面的数据,但不建议在这里进行修改
            commit,
            state
        }, user) {
            // 请求后台服务修改用户数据
            axios.post('/user/changeUser', user)
				.then(r => {
					if (r.data.code == 0) {
                		// 修改用户成功,使用commit分发操作到mutation
						commit('SET_NAME', user)
					}
				})
        }
    }
}

export default user

业务代码调用Action

this.$store.dispatch('changeUser', user)

// 若需要在Action执行成功或失败后执行回调,可这样写
this.$store.dispatch('changeUser', user)
    .then(res => {
        alert('change success')
    })
    .catch(res => {
        alert('change fail')
    })

index.js

index.js的作用是初始化Vuex,并聚合所有的模块将其挂载到Vuex的Store中,供全局调用

import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import getters from './getters'

// 引入Vuex
Vue.use(Vuex)

// 初始化Store
const store = new Vuex.Store({
    // 聚合所有的模块,这里仅有user
    modules: {
        user
    },
    getters// Getters也需要在这里挂载到Store中
})

export default store

当然还需要在main.js中引入上面的index.js,并挂载到Vue对象上,供全局调用

//./store/index和./store都可以,如果省略index vue会自动寻找index
import store from './store'
Vue.prototype.$store = store

getters.js

const getters = {
    getUser: state => {
        // 我们可以在这里将user组合成对象,方便使用
		return {
            name: state.user.name,
            age: state.user.age,
            school: state.user.school,
        }
	}
}
export default getters

业务代码使用State数据

以下两种用法都可以实现数据响应式实时更新

<!--从getter中获取-->
<div>{{$store.getters.getUser.name}}</div>
<!--直接从state中获取-->
<div>{{$store.state.user.name}}</div>

要不要用Vuex?

对于Vuex我们基本有了一个比较清晰的认知,那么在什么时候我们的程序应该使用Vuex呢?

官网为我们给出了答案:

Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

参考文章:

https://www.cnblogs.com/Leophen/p/11271713.html

《Vue前端开发快速入门与专业应用》–陈陆杨

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值