vuex详解一:彻底弄懂state、mapState、mapGetters、mapMutations、mapActions

2023-11-01

一 、state

先看一下标准的store目录结构

入vuex 以后,我们需要在state中定义变量,类似于vue中的data,通过state来存放共享的1状态

-store
 --actions   
 --mutations
 --getters
 --mutations-type
 --index.js复制代码

index.js是总入口

importVuefrom'vue'importVuexfrom'vuex'Vue.use(Vuex)

import state from'./state.js'import actions from'./actions.js'import mutations from'./mutations.js'import getters from'./getters.js'exportdefaultnewVuex.Store({
  state,
  actions,
  mutations,
  getters
  
})

复制代码

我们在state.js中定义变量

exportdefault {

  userInfo:{
	userName:"油炸皮卡丘",
	age:"22",
	sex:"女"
  },
  token:"aerfrftregtyrb.rytyuhjyi",
  friends:["Tom","Herry","Lucy"],
  likes:["吃饭",'睡觉','看电影'],
  money:250
}
复制代码

在组件中使用,在App.vue中自定义两个组件

<divid="app"><about></about><home></home></div>复制代码

about.vue里面的内容

<h1>{{$store.state.userInfo.userName}}</h1> //油炸皮卡丘
复制代码

home.vue里面的内容

<h1>{{$store.state.userInfo.age}}</h1> //22
复制代码

如图,显示出显示出相应的内容,有了vuex,我们不必在考虑组件之间的传值,直接就可以通过$store来获取不同的数据

但是如果需要vuex中的多个数据的这时候,这样写就太啰嗦了,我们可以将它定义在computed中。

props,methods,data和computed的初始化都是在beforeCreated和created之间完成的。

例如

<template>
  <divclass="home">
    {{userName}}
  </div>
</template>
<script>exportdefault {
  name: 'home',
  computed:{
    userName(){
      returnthis.$store.state.userInfo.userName
    }
  }
}
</script>复制代码

这样引入就方便了很多。

1.2 mapState辅助函数

使用this.$store.state虽然可以很方便的将state里面的值融入computed,但是如果要取多个值,就会出现以下的情况

computed:{
    userInfo(){
      returnthis.$store.state.userInfo
    },
    
   token(){
      returnthis.$store.state.token
    },
    
     friends(){
      returnthis.$store.state.friends
    },
    
    likes(){
     returnthis.$store.state.likes
    },
    ...
  }
复制代码

特别多的话就会很麻烦,而这时候vuex又给我们提供了更简便的方法mapState方法,

该方法就可以自动将需要的state值映射为实例的计算属性

我们可以这样写

import {mapState} from'vuex'exportdefault {
  name: 'home',
  computed: mapState(['likes','friends','token','userInfo'])
}
复制代码
mapState(['likes','friends','token','userInfo']) //填入哪些字段就会将这些字段自动映射为一个计算属性复制代码

所以

mapState(['likes','friends','token','userInfo'])

复制代码

等价于下面的代码

userInfo(){
  returnthis.$store.state.userInfo
},

token(){
  returnthis.$store.state.token
},

 friends(){
  returnthis.$store.state.friends
},

likes(){
 returnthis.$store.state.likes
},
复制代码

记住:用mapState等这种辅助函数的时候,前面的方法名和获取的属性名是一致的。

如果我们需要自定义一个计算属性怎么办呢?怎么添加呢?

毕竟现在已经成这样了 computed: mapState(['likes','friends','token','userInfo'])

这时候我们就需要es6中的展开运算符:...。将mapState映射的计算属性追加上去,而不是覆盖原有的

computed: {   
  value(){
   returnthis.val++
  },
  ...mapState(['likes','friends','token','userInfo'])

}
复制代码

在模板中使用

<h2>{{userInfo.userName}}</h2> //油炸皮卡丘
复制代码

关于别名

有时候,我们映射的时候,想给计算属性起个新的名字,不想用原有的属性名,那就可以像下面这样做,用对象的形式去别名

computed: {   
  value(){
   returnthis.val++
  },
  ...mapState({
      myLikes:"likes",
      myFriends:"friends",
      theUserInfo:"userInfo"
  })

}
复制代码

这样我们就可以在模板中使用

<h2>{{theUserInfo.userName}}</h2> //油炸皮卡丘
复制代码

二、getters

getters相当于vue中的计算属性,能拿到state里面最新的值

而且getters允许传参,第一个参数就是state

这样,通过getters进一步处理,得到我们想要的值,

getters.js

exportdefault{
    
    realName:(state)=>{
      return state.userInfo.userName+''
    },
    myMoney:(state)=>{
      return (state.money/7).toFixed(2)
    }
}
复制代码

在实例中我们可以这样用

computed: {  
 valued(){
   returnthis.value++
 },
 realName:this.$store.getters.realName,
 myMoney:this.$store.getters.myMoney,
}

复制代码

2.2 mapGetters辅助函数

mapGetters函数具有mapState的作用,而且其主要用法也是一样的,也能将getters的属性映射到实例的计算属性

computed: {  
 valued(){
   returnthis.value++
 },
 ...mapGetters(['realName','myMoney'])
}
复制代码

同样也可以取别名

computed: {  
 valued(){
   returnthis.value++
 },
 ...mapGetters({
     myRealName:"realName",
     myFormatMoney:"myMoney"
 })
}
复制代码

但有人就要问了,二者的作用实际上都一样?到底用哪个?或者说二者还有什么实质上的区别?

上面说过,getters可以传参,这才是getters和mapState的区别

那么如何传参呢?

getters的第一个参数是state

有这样一个场景,我们不想取所有的state里面的friends值,而是想根据我们传入的值筛选一下

那我们只要在getter返回的值套上一层函数那我们就可以实现传参数

exportdefault{
    
    realName:(state)=>{
      return state.userInfo.userName+''
    },
    myMoney:(state)=>{
      return (state.money/7).toFixed(2)
    },
    
    myFriend:(state)=>{
         //返回一个函数用于接收我们传入的筛选值returnfunction (friendName) {
           return state.friends.find(item => item === friendName)
       }
    }
}

复制代码

很显然,getters不仅可以像mapState一样拿到state里面的值,而且还可以在拿到之前,对值进行我们想要的加工

从而“派生”一些新的值,以满足我们不同的业务需要

淡然,如果不需要派生新的值,

this.$store.getters.值  就等于 this.$store.state.值
复制代码

三、mutation

我们代码中定义的时候需要些mutations,它类似于vue中的methods,

mutations需要通过commit来调用其里面的方法,它也可以传入参数,第一个参数是state,第二个参数是载荷(payLoad),也就是额外的参数

我们只能通过mutation去更改state里面的值

mutations.js

exportdefault {
    addAge:(state,payLoad)=>{
     state.userInfo.age+=payLoad.number
   },
   
   changeName:(state,payLoad)=>{
     state.userInfo.userName+=payLoad.userName
   },
   
   addFriend:(state,payLoad)=>{
      if(state.friends.indexOf(payLoad.newFriend) < 0){
          state.friends.push(payLoad.newFriend)
      }
   },
   
   setUserInfo:(state,payLoad)=>{
       state.userInfo=payLoad.userInfo
   },
   
   setToken:(state,payLoad)=>{
       state.token=payLoad.token
   }
    
}

复制代码

在模板中使用

<div class="home">
   <button @click="handleAddAge">增加一岁</button>
   <button @click="handleAddFriend">增加一个朋友</button>
</div>
复制代码

js部分

methods:{
 handleAddAge(){
 //使用mutation不像之前state、getters一样直接点调用,而是用commit关键字来提交mutationthis.$store.commit('addAge',{
     number:1
   })
 },
 
 handleAddFriend(){
     let name="皮卡丘";
     this.$store.commit('addFriend',{
     newFriend:name
   })
     
 }
}
复制代码

调用的时候第二个参数最好写成对象形式,这样我们就可以传递更多信息。

this.$store.commit('mutationName',{
  key1:val1,
  key2:val2,
  key3:val3
})
     
复制代码

但是,这样写还是会遇到同样的问题,就是如果需要操作多个数据,就会变的麻烦,这时候我们就需要mapMutations,通过它将方法映射过来

3.1 mapMutations辅助函数

跟mapState、mapGetters一样

不同的是,mapMutations是将所有mutations里面的方法映射为实例methods里面的方法

所以我们可以这样用

methods:{
 ...mapMutations(['addAge'])
}
复制代码

mapMutations(['addAge'])这一句就相当于下面的代码

methods:{
 addAge(payLoad){
 
  this.$store.commit('addAge',payLoad)
 }
}

复制代码

参数我们可以在调用这个方法的时候写入

<button @click="AddAge({number:1})">增加一岁</button>
复制代码

同样也可以有别名

methods:{
 ...mapMutations({
     handleAddAge:'addAge'
 })
}
复制代码
<button @click="handleAddAge({number:1})">增加一岁</button>
复制代码

这时候有些人要说了,我为什么要绕一圈,从mutations里面去改state呢?我能不能直接改state呢?

比如这样:

addAge(){
 this.$store.state.userInfo.age +=5;
}
复制代码

实际看结果也可以,那我为什么从mutations里面中转一下呢?

原因如下:

  • 在mutations中不仅仅能做赋值操作

  • Vue.js在mutations中做了类似埋点操作,如果从mutations中操作的话, 能被检测到,可以更方便用调试工具调试,调试工具可以检测到实时变化,而直接改变state中的属性,则无法实时监测

注意:mutations只能写同步方法,不能写异步,比如axios、setTimeout等,这些都不能写,mutations的主要作用就是为了修改state的。
原因类似:如果在mutations中写异步,也能够调成功,但是由于是异步的,不能被调试工具追踪到,所有不推荐这样写,不利于调试,这是官方的约定。

3.2 使用常量替代Mutation事件类型

把原本的方法名称由字符串转变成常量

mutations.js

constADD_AGE ='addAge'constCHANGE_NAME ='changeName'constADD_FRIEND='addFriend'constSET_USER_INFO='setUserInfo'constSET_TOKEN='setToken'//然后用常量替换原有的方法名exportdefault {
    [ADD_AGE](state,payLoad){
     state.userInfo.age+=payLoad.number
   },
   
   [CHANGE_NAME](state,payLoad){
     state.userInfo.userName+=payLoad.userName
   },
   
   [ADD_FRIEND](state,payLoad){
      if(state.friends.indexOf(payLoad.newFriend) < 0){
          state.friends.push(payLoad.newFriend)
      }
   },
   [SET_USER_INFO](state,payLoad){
      state.userInfo=payLoad.userInfo
   },
   
   [SET_TOKEN]:(state,payLoad)=>{
       state.token=payLoad.token
   }
    
}

复制代码

为什么这样写?

  • 不容易写错,字符串容易写错,而且字符串写错以后不会报错位置,而用常量替代,如果写错,eslint可以提示错误位置

  • 当使用action派发mutation时,在action中使用同样的常量,避免手滑写错方法

用常量替代mutations的时候我我们可以新建一个文件(mutation_type.js)专门存储这些常量

mutation_type.js部分

constADD_AGE ='addAge'constCHANGE_NAME ='changeName'constADD_FRIEND='addFriend'constSET_USER_INFO='setUserInfo'constSET_TOKEN='setToken'export  {
   ADD_AGE,
   CHANGE_NAME ,
   ADD_FRIEND,
   SET_USER_INFO,
   SET_TOKEN
}
复制代码

然后在mutations.js中引入

import {
    ADD_AGE,
    CHANGE_NAME,
    ADD_FRIEND,
    SET_USER_INFO,
    SET_TOKEN
} from"./mutation_type.js"exportdefault {
    [ADD_AGE](state,payLoad){
     state.userInfo.age+=payLoad.number
   },
   
   [CHANGE_NAME](state,payLoad){
     state.userInfo.userName+=payLoad.userName
   },
   
   [ADD_FRIEND](state,payLoad){
      if(state.friends.indexOf(payLoad.newFriend) < 0){
          state.friends.push(payLoad.newFriend)
      }
   },
   [SET_USER_INFO](state,payLoad){
      state.userInfo=payLoad.userInfo
   },
    [SET_TOKEN]:(state,payLoad)=>{
       state.token=payLoad.token
   }
    
}

复制代码

四、actions

action类似于mutation

我们只需要记住一下几点:

  • action可以提交mutation,然后mutation去更改state

  • action不要直接去操作state,而是去操作mutation

  • action包含异步操作,类似于axios请求,可以都放在action中写

  • action中的方法默认的就是异步,并且返回promise

为什么?因为这是Vuex规定的

actions.js

import {
    ADD_AGE,
    CHANGE_NAME,
    ADD_FRIEND,
    SET_USER_INFO,
    SET_TOKEN
} from"./mutation_type.js"exportdefault{

   
   //定义一个异步获取用户信息的actionasyncgetUserInfo(context){
       //context可以理解为它是整个Store的对象.类似于this.$store,里面包含了state,getter,mutations,actionsconst res = await axios.get('/接口url')
       
       //这个时候就用到了 mutation_type.js
       context.commit( SET_USER_INFO,{userInfo:res.userData}
       )
    },
    
    //定义一个异步获取用户token的actionasyncgetToken(context){
         const res = await axios.get('/接口url')
         context.commit(
             SET_TOKEN,
             {token:res.token}
       )
    }
    
}

复制代码

当然,我们可以通过解构的方式,将context对象里面的属性解构

asyncgetUserInfo:({commit,dispatch})=>{
       const res = await axios.get('/接口url')
       commit( SET_USER_INFO, {userInfo:res.userData})
    }
复制代码

想想一个实际开发场景,state里面的userInfo属性值是空的,当登录以后,再进行获取对应的信息。

登录以后,需要得到用户信息显示到界面上,那如何得到呢?

首先进入页面的时候调用actions中的getUserInfo方法

vue部分


<template>
    <div>{{realName}}</div>
</template>



exportdefault{
    computed(){
    //第三步realName:this.$store.getters.realName
},


created(){ 
    //第一步this.reqUserInfo()
},
methods:{
    reqUserInfo(){
       //第二步使用action不想之前state、getters一样直接点调用,而是用dispatch关键字来派发actionthis.$store.dispatch('getUserInfo')
    }
}
    
}
复制代码

来梳理一下上面的流程

  1. 页面初始化时调用 this.reqUserInfo()方法。 this.reqUserInfo()派发一个名为getUserInfo的action

  1. 在getUserInfo这个action中,我们执行了如下操作:

asyncgetUserInfo(context){
      //1.从接口里异步获取数据const res = await axios.get('/接口url')
      
      //2.将获取到的数据,通过commit提交一个mutation,去更改state里面的userInfo
      context.commit( SET_USER_INFO,{userInfo:res.userData})
   },
复制代码
  1. 在computed中拿到最新的用户信息的用户名

//3.拿到最新的userInfo
  realName:this.$store.getters.realName
复制代码

所以看到这里,大家应该明白Vuex所谓的单向数据流

界面——>派发action——>action提交mutation——>mutation更改state——>getters返回最新的state值到界面

4.1 mapActions辅助函数

mapActions和mapMutations一样,它将actions里面的方法映射到methods

所以,当action多了,我们可以这样使用

methods:{
    ...mapActions(['getUserInfo','getToken'])
}

复制代码

相当于

methods:{
    getUserInfo(){
        returnthis.$store.dispatch(‘getUserInfo’)
    },
    getToken(){
        returnthis.$store.dispatch(‘getToken’)
    },
}
复制代码

当然也可以有别名

methods:{
    ...mapActions(
      {reqUserData:'getUserInfo'},
      {reqToken:'getToken'},
    )
}

复制代码

另外,补充一下

可以在action派发别的acton,如下

asyncgetUserInfo(context){
    
       const res = await axios.get('/接口url')
       context.commit( SET_USER_INFO,{userInfo:res.userData})
       
       //此处派发另外一个action
       context.dispatch('getToken') 
    },
复制代码

5、总结一下

  • 依赖state得到新的数据,用this.$store.getters.值

  • 直接获取state的数据,用this.$store.state.值

  • 同步修改state的属性值,就用this.$store.commit('mutation值')

  • 异步修改state的属性值,就用this.$store.dispatch('action值')

  • mapState、mapMutations、mapGetters、mapActions等辅助函数,便于我们处理多个方法和属性

作者:清风夜半

链接:https://juejin.cn/post/6969553033545941022

来源:稀土掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vuex详解一:彻底弄懂state、mapState、mapGetters、mapMutations、mapActions 的相关文章

随机推荐

  • MII接口及应用

    MII是英文Medium Independent Interface的缩写 翻译成中文是 介质独立接口 该接口一般应用于以太网硬件平台的MAC层和PHY层之间 MII接口的类型有很多 常用的有MII RMII SMII SSMII SSSM
  • sink 写入本地文件(八)

    sink 写入本地文件 2 4 Sink 2 4 1 将数据写入文件 File Sink 2 4 Sink Flink 没有类似于spark中 foreach 方法 让用户进行迭代的操作 虽有对外的输出操作都要利用Sink完成 最后通过类似
  • 软件工程 第一次随堂练习

    以下答案是经过人工智能生成 个人理解得出的答案 若有不同见解 请在评论区留言或私信 说明下列需求分别属于下面的哪种类型 为什么 A 业务需求 B 用户需求 C 系统级 功能 需求 D 性能需求 E 质量需求 F 约束 G 对外接口 H 数据
  • linux的aix下的makefile参考

    一 详解 1 简单模板makefile CC OBJS CFLAGS TARGET all TARGET TARGET OBJS CC CFLAGS o OBJS SUFFIXES o h SUFFIXES cpp o cpp o CC c
  • APP首次进入,弹出服务协议和隐私政策

    app上应用市场里需要几个条件 需要第一次下载并进入首页前展示用户协议和隐私政策弹窗提醒 以及在应用内版块有常驻入口 就是应用里有可以看到这个协议的版块 登录或者注册页面也需要有同意服务协议和隐私政策的提醒 在上个项目上线时候遇到andro
  • 服务器管理口安装系统,管理口安装服务器操作系统

    管理口安装服务器操作系统 内容精选 换一换 如果Windows操作系统云服务器未安装密码重置插件 可以参见本节内容重新设置密码 本节操作介绍的方法仅适用于修改Windows本地账户密码 不能修改域账户密码 Linux操作系统请参见重置Lin
  • Golang 从零开始实现多人聊天室(五)开发前奏-目录结构优化

    系列文章目录 跟着 猫猫学Golang 快人一步 系列初开 跟着我走进Go 语言的世界里 系列目录 Golang 从零开始实现多人聊天室 一 服务端监听 Golang 从零开始实现多人聊天室 二 客户端访问 Golang 从零开始实现多人聊
  • 图像阈值cv2.threshold

    图像阈值 图像阈值函数 图像阈值函数 ret dst cv2 threshold src thresh maxval type src 输入图 只能输入单通道图像 通常来说为灰度图 dst 输出图 thresh 阈值 maxval 当像素值
  • (如何安装pytorch详细教程!!!)全面讲解安装Anaconda+CUDA+PyTorch

    之前安装了CUDA 与Pytorch 但是当把自己的数据放到GPU上训练的时候 代码部分已经写清楚放到CUDA上 发现GPU的占用率很低 CPU的占用率高达90 后来发现是显卡的驱动与自己安装的CUDA并不匹配 pytorch与cuda的版
  • 三组计算机局域网组网方案,怎么建立一个可以互相联机的局域网

    都是xp的就好办了 在网上邻居里 先设置家庭或小型办公网络 然后添加邻居就可以了 你试下 不行的话 下面的资料你参考下 goodluck 家庭或小型办公室 如果有两台或更多的计算机 很自然地希望将他们组成一个网络 为方便叙述 以下约定将其称
  • kubernetes集群实战--master节点及node节点的部署搭建(二)

    kubernetes集群的安装部署 1 基础环境部署 准备三台虚拟机 主机名 IP地址 角色 k8s master 192 168 100 8 master node k8s node1 192 168 100 9 node1 k8s no
  • 使用ppocr突然退出问题

    本次使用conda装了一个cuda10 2版本的paddleocr 然后所有的环境检查没问题 使用paddle自带的检查代码 输出提醒paddle可以正常使用 gt gt gt import paddle gt gt gt paddle u
  • QT 鼠标事件及labe显示设置总结

    qt鼠标事件总结 转 1 QMouseEvent中的坐标 QMouseEvent中保存了两个坐标 一个是全局坐标 当然另外一个是局部坐标 全局坐标 globalPos 即是桌面屏幕坐标 screen coordinates 这个跟windo
  • Edge浏览器查看请求头(2022)

    目录 如何查看 使用公开的 如何查看 OK如果大家找不到的话可以用下面的这些在网上已经公开的请求头 使用公开的 Mozilla 5 0 Windows NT 10 0 Win64 x64 AppleWebKit 537 36 KHTML l
  • 报错 java.lang.NoClassDefFoundError: Lcom/sun/tools/javac/util/List;

    解决办法 全局搜索javac 找到引用的地方 import com sun tools javac util List 把它删除 重新引用 import java util List 原因 jar包引用错误
  • C++(18)——智能指针unique_ptr

    简介 unique ptr 是 C 11 提供的用于防止内存泄漏的智能指针中的一种实现 独享被管理对象指针所有权的智能指针 unique ptr对象包装一个原始指针 并负责其生命周期 当该对象被销毁时 会在其析构函数中删除关联的原始指针 u
  • spwan-fcgi和fcgi 关系

    spwan fcgi 举个例子 spawn fcgi a 127 0 0 1 p 10000 f login spwan fcgi c main 函数 会执行参数解析过程 获得 ip 端口 和 执行文件的路径 bind socket 函数会
  • Ubuntu22 k8s 1.27.1 安装及集群搭建教学(2023.5.16 k8s 最新版本教学,只看这一篇就够了哦!保姆级教程!不行你来找我!)

    Ubuntu22 k8s 1 27 1 安装及集群搭建教学 2023 5 16 k8s 最新版 只看这一篇就够了哦 保姆级教程 不行你来找我 温馨提示请仔细阅读 1 由于新版的k8s不支持docker了 因此开始前建议新开一台全新的虚拟机
  • Java finally return执行顺序

    Java finally语句到底是在return之前还是之后执行
  • vuex详解一:彻底弄懂state、mapState、mapGetters、mapMutations、mapActions

    一 state 先看一下标准的store目录结构 入vuex 以后 我们需要在state中定义变量 类似于vue中的data 通过state来存放共享的1状态 store actions mutations getters mutation