Vuex到底如何使用

一、简介

1.1什么是Vuex

官方的定义如下:

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

官方的解释看的一团迷雾,简单来说就是把一堆可能很多地方(各组件)会用到的数据管理起来,可以对这些变量进行修改,需要的时候就去取。

2.两个小例子:

1) 在项目中很多地方都要进行请求,vue中一个页面的每个组件都可能会有请求,服务器每次请求都需要判断用户的权限、token等信息,这里就可以把用户的权限信息、token等放入一个单独的仓库里面进行管理,每个组件都能对其状态(说白了就是值)进行读取、修改。

说到这里,可能有很多人就会说,这些信息直接放进cookies和session里面就行了啊,干嘛还要单独弄一个空间来存放这些信息。实际上,更多的时候是使用cookie与vuex配合一起使用,vuex获取信息,cookie控制时间和token的销毁。

2) 基于Vue的组件开发,肯定避免不了组件间的传参,父子传参还好说,直接使用prop传,或者父组件调用子组件的函数(使用emit/on)。但涉及到非父子组件之间的传参,常规的办法是建立一个空组件event bus,通过这个中间组件来传参,但这种方式只适用于不涉及到大量的信息传递,涉及到多个组件之间传参的时候,显然event bus就不适用了,这时候vuex就派上用场了,后面会对比vuex和event bus的区别。

所以,说白了,你可以把vuex看做一个数据库,把可能多个组件会用到的共享的参数放到里面,每个组件都可以获取和修改这些数据,用来解决多组件共享一个数据和组件间的通信问题。

说起存储数据,可能有些小伙伴或会想起localstorage,需要注意的是,vuex适用于单页面开发的,如果刷新页面了,或者页面跳转了(注意,是跳转页面,不是页面中组件改变),那vuex中的数据就自动清空了。而localstorage是一种物理存储,是针对于整个应用(application)的,页面刷新数据依然存在。后面也会介绍vuex和localStorage的区别。

二、应用原理

1.原理简述

既然说到vuex相当于一个数据库,那肯定就要定义里面存储那些信息、如何读取或者使用里面的变量,定义的这个文件就是store.js,现在来讲这个store.js里面是如何定义要用到的变量和使用变量的方法的。

store.js里面主要分为了一下几个模块:

1)state: 这里面就定义了我们存入的变量,它可以是任何类型的变量,在此定义之后,才能在vue的组件里面获取。

2)mutation: 定义更改state中变量状态的函数,所有对state中变量的修改只有一条途径,就是通过调用mutation中定义的对变量的操作方法,通过在组件中使用storage.commit(“定义的函数名”,参数)来修改、提交、删除state中的变量。

3)action:刚才说的mutation中定义的方法是同步的,假若想支持异步,比如在其中加入axios请求,就需要在action中定义函数,然后将mutation中的函数作为回调,执行storage.commit(“定义的函数名”,参数),达到异步的效果。关于mutation和action后面会单独分析。

4)getter类似于组件中的计算属性,当需要对state里面的变量进行一些计算再返回的时候,就要使用getter。他会接受state作为顶一个参数,然后从state中获取相应的变量进行计算,返回计算值。

5)module

当state中的变量越来越多,共享参数涉及到的组件也越来越多,如果不进行分类,就会显得比较臃肿,不利于维护,module的作用就是将store分模块,每个模块拥有自己的state/mutation/action,便于维护。

2.了解了以上之后,来看一个简单的例子:

准备好环境之后(搭建vue项目),引入vuex:

npm install vuex --save

src目录下建立store文件夹,文件夹中新建store.js文件,下面是一个简单的store,js:

 

这样,就可以在组件中引入store,

通过使用store.state.user获取user,

使用store.commit(“setUser”,”fanrui”)修改属性值;

使用dispatch(“commitUser”,”fanrui”)来进行异步的操作。

3.模块化

上面是一个简单的小例子,刚才说了,对于涉及模块比较多,那这里可以引入module,结构目录如下:

 

一个一个来看,这里将所有状态量分为了六个模块(对应modules下的六个文件),每个文件里面都自定义了自己的state、mutation,action,例如user.js文件下:

 

然后在统一的一个index.js(这里的index.js就是store.js,可以自己命名)文件中设置每个模块的对外输出:

 

在组件中使用时只需要引入外层store文件夹即可调用:

        

Store.state.user.token获取user中的变量

Store.state.user.commit() 调用user中的mutation方法修改变量

Store.state.user.dispatch()调用user中的action的方法异步执行

这就是采用module的方法,有些同学可能觉得每次调用都要写Store.state.user这么长一串比较麻烦,别担心,vuex提供了一个mapActions辅助函数,解决这个问题。具体使用方法在后面解释。

最后一个,解释一下这个getter.js,刚刚说了这个getter相当于计算属性,其实看一下这个getter.js文件,你可能就明白了

 

getter里面定义了各种计算变量,默认传入的参数就是整个store的state变量,可以利用state中的任意变量来进行计算,得到想要的属性进行输出,在组件中只需引入getter.js,就可以获取相应状态。   

三、补充说明

1.Vuex和eventbus

先来看看各组件的传参:

1.1 父—>子:

每个子组件上都有一个prop,需要传递的参数放入其中,父组件可以把参数传给子组件,例如:

   父组件中使用子组件,并定义想要传过去的参数: 

子组件通过prop接收:

  

1.2 子—>父:

子组件可以用vue.$emit传递往上传递消息,父组件通过vue.$on回应子组件穿过来的消息:

   子组件中:

        this.$emit(“todo”,{

res: ”子组件发送的消息”
)

父组件中:

this.$on(“todo”,function(data){

     data为传的消息,对data进行处理

})

1.3 兄弟组件间的传递:

emit/on只能在上下层之间传递消息,兄弟之间使用事件总线event bus传递。Evnetbus就相当于一个顺丰快递,将参数在组件传递;首先新建一个传递的媒介bus.js,为空就行,在需要传递的组件中引入bus.js,在一个组件间传出:

        bus.$emit(“queryParam”,message)

在另一个组件中接受:

        bus.$on(“queryParam”,message=>{…….}) 

这里多个组件都可以接受同一个组件发出的消息,只要第一个参数名相同就行。

 1.4 Eventbus缺点: 

这就是组件间的传参,既然已经实现,哪位什么还要引入vuex?

在最开始,我们的项目可能比较简单,但当项目越来愈大,组件越来越多,组件之间的交互也越来越多,组件里就会不断出现$emit这样的代码,主要产生以下几个问题:

1)代码变的冗余,可读性下降(总之就是看着好累,不舒服)

2)对于每一个组件都需要使用emit或者on来处理,设置不同的通信函数(emit、on的第一个参数)

2)很难查找每个事件是从哪里触发的,因为到处都是关于传参的业务逻辑

1.5 小例子说明:

说到这里可能对两者的区别有了些了解,但具体到应用中的区别还不是特别清楚,下面来举一个计数器的小例子。

有一个根组件,姑且叫做S,里面有一属性count。

需求1,写一个组件A作用是实现其中的按钮一次,然后将count计数加一,并在自身的组件中展示当前count的数字;这个比较好办,点击时count计数加1,同时使用event bus将参数count传递到根组件中,进行根组件的展示。

需求2,写一个组件B,作用是将组件S中的count数值为0,这个也好办,直接使用event bus向S组件发起$emit,S接收后,将count置为0;

问题在于,当你点击A组件时,在S组件和A组件上的count都会加1,但是当点击B时,S组件中的count变为0了,但是A组件的count不会发生变化,因为B组件只通知了S,并不知道到A组件会展示count,这就是问题的所在。

 有的小伙伴会说,这不简单,在B中在写一个emit传给A就可以了;的确,这是一个办法,但上面说过了,这只适用于组件较少的情况,当你的组件比较多的时候,就会出现问题

比如在这里有多了个C组件、D组件同样是对count进行操作,也要展示count,那我们是不是得在这些组件之间为每一个组件都写一个emit进行传递,假设有N各组件,那是不是就总共得写N*N+1个emit/on?

第二个问题在于,你在添加组件的时候,你可能并不知道有哪些组件使用到了count,就像上面的例子一样,B只通知了S,而没有通知A。假设在一个项目开发过程中,突然有一个需求让你添加一个对count的操作,暂且不说你要写多少个emit,问题在于你首先得知道在之前有哪些组件用到了count,这也是个问题。

所以针对这种类似的问题,使用vuex是不是更加合理呢,下面来看看vuex是怎么解决上面的问题的吧:

第一个解决的是上面通知组件的问题:

引入vuex之后,将我们的countState放进store的state中作为共享变量,将countState映射到count中,这样每个组件中的count就会随着countState的改变而改变(数据是响应式),任何地方对countState的操作都会映射到各组件中,只要仓库中的countState改变了,各组件中的count也随着更新。

第二个是解决所有组件对状态的操作问题:

比如在需求的增加中,突然对count的大小做个规定,小于50,那对应是不是每个组件对countState进行操作的时候都要先判断其值是不是小于50?这个时候vuex提供了mutation方法,提供对countState变量统一的处理方法,此时就可已在这个方法中加入其值小于50的判断,就不用了在每个组件中单独判断了,将这个逻辑放到vuex中处理,组件只需要调用相应commit方法就行,例如下面的方法:

 mutation:{

    setCountState(state){
            if(state.countState < 50)
             {
                state.countState+=1;

}

else{

          state.countState = 0

}
    }

1.6 结论

在大型应用方面,vuex是一个比eventBus好的解决方案。

Vuex式结构更加清晰,更易调试。

若果不涉及到大量的共享数据、组件通信,其实eventbus就足够了,但是。。。。个人还是觉得vuex用着舒服点。

  1. Vuex、LocalStorage:

  Vuex和LocalStorage都可以用存储数据,对于LocalStorage我会另写一篇文章来详细的描述其原理,这里只单纯的讲一讲这两者的区别:

2.1 区别:

先说说存储方式,Vuex是存在内存中的,而localStorage是存在文件中的,并且localStorage的存储到小有限制,为5M

LocalStorage以文件形式存到本地,主要用于页面间的传参,不同页面通过访问storage记性传参;而vuex主要实在单页面内进行组件间的传值,为响应式数据(重点),各组件可以对其进行修改。

由此可以得出结论,在数据是静态不变的情况下,可以使用LocalStorage;当数据被多个组件共同使用,且要求数据改变后达到响应数据的变化的要求,则使用vuex。

2.2常见用法:

其实一般这两者可以搭配使用,由于LocalStorage不能相应数据的变化,所以一般将LocalStorage的操作写在vuex的mutation里面,使其随着vuex的变化而进行够改变;而对于多页面或者页面刷新之后,vuex将会被清空,这个时候就需要从LocalStorage里面取数据,填补vuex;不过需要注意的是:

vuex和LocalStorage要进行同步更新,这个就是在vuex数据改变之后,在mutation对应的方法中把值传到LocalStorage中;

存入vuex和LocalStroage是否有失效时间,比如像存储用户名、密码、token等这样的字段,就要控制这些变量失效时间;

不是所有放在vuex里面的变量都要在放到LocalStorage里面一份,对于刷新页面或者页面跳转(注意是页面跳转而不是组件跳转)涉及到需要保存内的数据存到LocalStorage里面就行了。

以上仅为个人理解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值