vuex学习篇(2024)
认识vuex
vuex是一个vue状态管理工具(状态就是数据)
vuex 是一个插件,可以帮我们管理 vue 通用的数据(多组件共享的数据)
vuex是单一组件树,只有一个store,但是可以分模块
状态管理:在开发中要处理各种各样的数据,这些数据需要保存在一个位置,对这些数据的管理就称为状态管理
之前在组件中进行数据管理,但是实际开发中项目很复杂,数据变多,还那样做项目会变得臃肿
vuex的核心是store仓库,本质上是一个容器,包含应用中大部分的状态state
- 理解:
比如一个购物车案例,你买了两个西瓜,那么这个2个西瓜和对应价钱这些数据不光会用在西瓜这个物品展示的组件上,还会用到结算金额的组件上,多组件共享数据的情景使用vuex可以帮我们管理 - 使用场景:
某个状态在很多个组件来使用(个人信息)
多个组件共同维护一份数据(购物车)
关键词:通用,多组件共享 - vuex优势:
共同维护一份数据,数据集中化管理
响应式变化(任何一个组件修改数据,所有用到这个数据的地方也都会对应修改)
操作简洁(vuex提供了一些辅助函数)
创建一个空仓库:
理解:既然要多组件共享数据,那么肯定要有个地方存放这些数据。安装vuex插件,初始化一个空仓库,将来的组件想要用数据在这里拿即可
步骤:安装 vuex;新建vuex模块文件(创建文件夹store,在下面创建index.js文件定义vuex,在main.js中挂载使用);创建仓库(new Vuex.Store());main.js导入挂载(在main.js中导入挂载到vue实例上)
安装vuex,创建空仓库
装包(后续如果在创建项目的时候把vuex勾选上那么其实不需要装包的,会自动帮你搭好):在终端输入npm add vuex@3 –force ,如果报错npm add vuex@3 –legacy-peer-deps(他人经验有备无患)
我用的第一个命令强制安装了,但是弹出了很多warn
要验证是否成功安装了vuex,在任意组件中使用一下,在组件中访问仓库,控制台打印一下 this.&store,如果成功那么能看到这个store,如果没成功那么现实undefind
index.js代码
1 | //这里面存放的就是 vuex 相关的核心代码 |
main.js代码
1 | import Vue from 'vue' |
核心概念-state状态
理解:已经有了空仓库,那么要给仓库提供数据,还要能使用仓库的数据
state:状态即数据(类似vue组件中的data)
data是组件自己的数据
state是所有组件共享的数据
提供数据:
state提供唯一的公共数据源,所有共享的数据都要统一放到store中的state中存储,在stste对象中可以添加要共享的数据
const store=new Vuex.Store({
store:{
//要添加的数据写在这里
数据名1:’早上好’,
数据名2:123
}
})获取使用数据
方法1:
通过store直接访问找到仓库,然后再找到仓库的state,再拿到数据
先获取store两种方法(1)this.$store(2)import导入store
在模板中
在组件逻辑中:this.$store.state.数据名
在js模块中:store.sttate.数据名
方法2:
通过辅助函数简化代码,mapState辅助函数帮助我们把store中的数据自动映射到组件的计算属性中,mapState辅助函数会自动生成数据映射
步骤:
(1)导入mapState,
在.vue中引入import{mapState}from ‘vuex’
(2)用数组方式引入state,mapState([‘数据名’])多个之间用逗号分开
(3)展开运算符映射,computed:{…mapState([‘数据名’])}多个之间用逗号分开
这样做以后.vue中使用数据不需要再,直接使用即可
核心概念-mutations
理解:vuex同样遵循单项数据流,意味着组件中不能能直接修改仓库的数据,如果任意组件都能修改仓库的数据,那么很难维护,所以要修改数据需要用到mutations
在store声明中增加代码strict:true开启严格模式,这样在组件中修改仓库数据会及时报错,但是上线后要关闭这行代码,因为监测消耗运行成本
通过mutations修改数据
理解:本质上是组件想要修改数据,仓库提供一个修改数据的党法,组件把修改请求提交给仓库,由仓库来进行修改操作
使用步骤:
- 在store声明的地方定义mutations对象,在对象中存放修改state的方法
1
2
3
4
5
6
7
8
9mutatios:{
state:{
count:0
},
mutations:{
addCount(state){
state.count +=1
}
}} - 在组件中提交调用mytations
在组件中的相关函数中
this.$store.commit(‘addCount’)
mutation函数传参语法
- 在mutations中对应函数提供参数
mutations:{
addCount(state,n){
state.count +=n
}
} - 在页面中提交调用mutation
this.$store.commit(‘addCount’,10)
辅助函数-mapMutations(简化方法代码)
mapMutations和mapState很像,它是把位于mutations中的方法提取了出来,映射到methods中
比如有函数
1 | mutations:{ |
你要在组件中用,可以
1 | import{mapMutations} from 'vuex' |
调用的时候需要this.subCount(100)
核心概念-actions
理解:处理异步操作,如一秒钟之后修改…
区别:mutations必须是同步的(便于检测数据变化,记录调试),而actions是处理异步操作的
比如下面的代码,context代表上下文,也可以理解为仓库
- 提供action方法
1
2
3
4
5
6
7actions:{
setAsyncCount(context,num){
//一秒后,给一个数,去修改 num
setTimeout(()=>{
context.commit('changeCount',num)},1000)
}
} - 页面中dispatch调用
this.$store.dispatch('changeCount',200)
注意,改数据都是mutations,但如果是异步,就在外面套一层dispatch
辅助函数-mapActions
mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中,化简methods
类似前面的辅助函数,在vue中只需要:
1 | import {mapActions }from'vuex |
核心概念-getters
类似组件中的计算属性,除了state之外还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters
理解:比如state中定义了一个list为1-20的数组,但是组件中要展示大于10的数据,那么此时纪要定义一个getters来找到大于10的数据state:{list:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]}
- 定义getters
注意:getters函数的第一个参数(形参)是state,而且必须要有返回值1
2
3
4
5getter:{
filterList(state){
return state.list.filter(item=>tiem>5)
}
} - 使用:访问getters
(1)通过store访问getters{{ $store.getters.filterList }}
(2)通过辅助函数mapGetters映射1
2
3
4computed:{
...mapGetters(['filterList'])
}
{{filterList}}
核心概念-模块module
由于 vuex 使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时
store 对象就有可能变得相当臃肿。(当项目变得越来越大的时候,Vuex会变得越来越难以维护)
理解:
vuex中和数据相关的所有东西都放在一起,那么当项目变大后和js文件的东西会变得越来越大难以维护,那么希望能够把这些东西才拆分成一个个小的模块,每一个小的模块里面装各自的state,mtation,action,getter
模块拆分:
在store文件夹下面新建一个modules文件夹,里面放xxx1.js,xxx2.js...(一个模块一个xxx.js)
每一个js文件就是一个模块
在每个.js文件中写各自的内容,在最后进行导出
如user.js代码
1 | const state ={ |
使用的时候在index.js中导入挂载代码
1 | import user from './modules/user' |
导出导入后,要验证是否配置成功,在调试工具看Root下面是否有子模块user
子模块中的state访问
尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的 state 中,属性名就是模块名。本质还是单一模块树,但是拆分子模块后可维护性高了很多
方法1;直接通过模块名访问$store.state.模块名.属性名
方法2:通过mapState映射
默认根级别的映射mapState(['属性名'])
子模块的映射mapState('模块名',['属性名'])
注意,需要开启命名空间:在子模块导出的地方第一行加上namespaced:true,可以理解为给一个一个模块起了不同的名字划分了不同空间
子模块中的getters访问
方法1;直接通过模块名访问$store.getters.['模块名/属性名']
方法2:通过mapGetters映射
默认根级别的映射mapGetters(['属性名'])
子模块的映射mapGetters('模块名',['属性名'])
注意,需要开启命名空间:在子模块导出的地方第一行加上namespaced:true
,可以理解为给一个一个模块起了不同的名字划分了不同空间
子模块中的mutation的调用和语法
默认模块中的mutation和actions会被挂载到全局,需要开启命名空间,才会挂载到子模块
调用子模块中的mutation:
方法1;直接通过store访问$store.commit.['模块名/属性名',额外参数]
方法2:通过mapMutations映射
默认根级别的映射mapMutations(['属性名'])
子模块的映射mapMutations('模块名',['属性名'])
注意,需要开启命名空间
子模块中的action的调用和语法
默认模块中的mutation和actions会被挂载到全局,需要开启命名空间,才会挂载到子模块
调用子模块中的action:
方法1;直接通过stores访问$store.commit.['模块名/属性名',额外参数]
方法2:通过mapActions映射
默认根级别的映射mapActions(['属性名'])
子模块的映射mapActions('模块名',['属性名'])
注意,需要开启命名空间