- vuex是什么?
- vuex的仓库中的五大核心概念
- 三、如何使用
- 四、如何分辨是否已经配置好vuex的仓库了呢?
- 五、组件中如何使用state与getter
- 方案二与方案三效果一样,一般我们更推荐大家使用方案三,但是在什么情况下要使用方案二呢?
- 六、如何修改仓库中的state与getter数据呢
- 七、使用action异步的修改state数据
- 方案一、使用$store.dispatch()来派发某个action。直接使用vuex绑定到vue原型上的$store这个对象的dispatch的方法。
- 方案二、在组件中先定义一个函数,函数名跟后续要调用的action名字保持一致,函数内部使用方案一。
- 方案三、使用mapActions这个辅助函数
- 八、vuex的module
- 四、仓库模块的局部状态
- getter语法
- action的语法
- 【注】!! mutation没有rootState这个东西。如果需要在mutation中使用其余模块的state数据的话,如何办?
- 五、v-model 绑定仓库中的数据的情况
vuex是什么?
vuex的仓库中的五大核心概念
- state 专门存共享数据的地方
- getter 可以针对现有的state数据或者其余的getter做的一个二次计算。可以理解为仓库。
- mutation 唯一能够修改state数据的东西
- action 异步操作,它里面可以写异步代码,它如果要修改state数据,是通过去调用mutation
- module 仓库模块的拆分
三、如何使用
- 项目中安装vuex
$npm install vuex
- 创建src/store.js文件。这个文件用来生效仓库的实例
- 需要在src/main.js文件的new Vue() 的位置去配置store选项,选项值是上一个步骤中暴露出来的store的实例。
四、如何分辨是否已经配置好vuex的仓库了呢?
查看vueDevtools 就可以、
五、组件中如何使用state与getter
方案一:使用挂载到Vue原型上的$store对象。这个$store就是 new Vuex.Store() 生成的仓库实例对象
方案二:(推荐)、使用computed
export default {
name: "World",
//2.1 使用mapState(语法糖函数)
// computed: mapState(["curCity", "cart"])
//2.2 mapState
computed: {
curCity(){
return this.$store.state.curCity;
},
cart(){
return this.$store.state.cart;
}
}
}
方案三:(推荐、就是方案二的一个优雅写法)使用vuex提供的辅助函数
- mapState
- mapGetters
- mapMutations
- mapActions
组件中引入你需要的辅助函数
//引入 辅助函数,采用类似解构赋值的方式
//import Vuex from "vuex";
//Vuex.mapState();
//Vuex.mapGetters();
import {mapState, mapGetters} from "vuex";
export default{
computed: mapState(['curCity','cart']);
}
调用赋值函数,并将其返回的值赋给组件的computed选项。
//引入赋值函数,采用类似解构赋值的方式
import {mapState, mapGetters} from "vuex";
export default {
//mapState 返回值是一个对象
computed: mapState()
}
- mapState 和 mapGetters 的语法
mapState([state1,state2,state3]);
//mapState 接收一个数组作为参数,参数中的每一项,就是仓库中的state数据
mapGetters([getter1, getter2]);
//mapGetters
方案二与方案三效果等价,但是在vueDevtools中的表现有稍微一点不同。但是不影响功能。
方案二时,插件显示的是computed
方案三时,插件中显示的是vuexbindings
方案二与方案三效果一样,一般我们更推荐大家使用方案三,但是在什么情况下要使用方案二呢?
希望组件中的数据与仓库中的数据用不同的名字的时候,采用方案二。
使用方案三时:我们组件如果还有一些自己的computed数据,该如何办?
- 将mapState()做展开,使用…做展开。
六、如何修改仓库中的state与getter数据呢
首先明确一点,state可以修改,getter不能修改
步骤:
1、仓库中要提供对应state修改的mutation函数
2、在组件中去调用mutation
调用mutation的三套方案
方案一、直接使用vuex绑定到vue原型上的$store这个对象的commit()方法
方案二、在组件中定义一个函数,函数名跟后续要调用的mutation名字保持一致,函数内部使用方案一。
方案三、使用mapMutations 辅助函数
//mapMutations的语法
//接收一个数组作为参数,数组中的每一项是一个mutation的名字
mapMutation([mutation1, mutation2, mutation3])
示例代码
{
methods: mapMutations(["SETCURCITY"])
}
实例代码转换就是如下的代码效果
{
methods: {
SETCURCITY(payload){
this.$store.commit("SETCURCITY", payload)
}
}
}
为了结合组件自身的函数,所以mapMutations也需要使用运算符去展开
methods: {
...mapMutations(["SETCURCITY", "ADDCART"]),
fn1(){
}
}
所有的mutation执行,都能够在VueDevtools去看到(可以注意一下时间旅行)
为什么vuex中的state必须使用mutation来修改呢
- 为了以一种可以预见的方式去修改数据,不至于让数据难以理解
- 为了实现时间旅行
七、使用action异步的修改state数据
首先需要知道,mutation里面只允许同步的去修改state数据。(虽然在mutation中可以异步的去修改state数据不会报错,但是会导致时间旅行等机制没有效果)
如果异步的修改的化,有两个大方案
1. 不涉及action,在组件上,异步代码走完之后,再去调用mutation
2. 使用action
使用action、首先需要在actions选项中定义action函数。
注意:action中不能直接去修改state,要修改是通过context.commit() 去执行某个mutation来修改。
方案一、使用$store.dispatch()来派发某个action。直接使用vuex绑定到vue原型上的$store这个对象的dispatch的方法。
//dispatch 语法
//actionName - 要调用的action的名字
//payload - 要传递这个action的参数
this.$store.dispatch(actionName, payload);
方案二、在组件中先定义一个函数,函数名跟后续要调用的action名字保持一致,函数内部使用方案一。
方案三、使用mapActions这个辅助函数
//mapActions的语法
//接收一个数组作为参数,数组中的每一项是一个action的名字
mapAction([action1, action2, action3])
示例代码:
{
methods: mapActions(['SYNCSETCURCITY'])
}
转换之后如下所示
{
methods: {
SYNCSETCURCITY(){
this.$store.dispatch('SYNCSETCURCITY', payload);
}
}
}
八、vuex的module
一、什么时候需要在vuex中使用module
项目越做越大,功能点越写越多,需要使用vuex共享的数据越来越庞大的时,就需要module来进行仓库模块拆分啦。
//拆分的仓库的子模块A
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
//仓库子模块也可以继续去做拆分,但是没有必要搞这么复杂
modules: {
aa,
ab
}
}
//拆分的仓库子模块B
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
//仓库根模块
const store = new Vuex.Store({
//通过modules选项配置子模块
modules: {
//key: value
// - key - 仓库子模块的名字
// - value - 对应的仓库子模块对象
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
二、仓库拆分子模块之后,没有设置命名空间有一些问题存在
默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的
- 多个仓库子模块的getters不能重名,getters数据是共享的(默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的)
- 多个仓库子模块中的mutation,如果同名的话,组件调用这个mutation时,都会被触发。
- 多个仓库子模块中的action,如果同名的话,组件调用这个action时。都会被触发。
三、由于有上面的这种问题存在,所以推荐仓库子模块设置上命名空间。
1. 如何设置呢?
给仓库子模块的那个对象配置一个namespaced属性。属性值为true。
2. 设置之后的改变是什么?
模块内部的action、mutation和getter是注册在自己的命名空间里的。
3. 设置了命名空间之后如何在组件中使用呢?
基本使用步骤不变,主要是处理命名空间
- 获取某个仓库子模块中的state(下面的xx代表某个仓库的子模块的名字)
//1. 直接通过$store
this.$store.state.xx
//2. computed
computed: {
name(){
return this.$store.state.xx.name;
}
}
//3. mapState
computed: {
...mapState("xx", [state1, state2, state3]);
}
//4. mapState 的转换
computed: {
state1(){
return this.$store.state.xx.state1
}
}
//5. 如果要在组件中同时拿到多个仓库子模块的同名state数据,不要使用mapState,请使用方案二?
- 获取某个仓库子模块的getter
//1、直接通过$store
this.$store.getters['xx/firstName']
//2. 使用computed
computed: {
firstName(){
return this.$store.getters["ma/firstName"];
}
}
//3. mapGetters 的转换
computed: {
getter1(){
return this.$store.getters["xx/getter1"]
}
}
3. 提交某个仓库子模块中的mutation
//1. 直接通过 $store
this.$store.mutations["xx/SET_NAME", payload];
//2. methods
methods:{
SET_NAME(payload){
this.$store.mutations["xx/SET_NAME", payload];
}
}
//3. mapMutaions
methods: {
...mapMutations:("xx", [mutations1, mutations2])
}
//4. mapMutations的转换
methods: {
mutations1(paylaoad){
this.$store.commit("xx/mutation1", payload);
}
}
4. 派发某个仓库子模块中的action
//1. 直接通过 $store
this.$store.dispatch("ma/SYNC_SET_NAME", payload);
//2. methods
methods: {
SYNC_SET_NAME(payload){
this.$store.dispatch("ma/SYNC_SET_NAME", payload);
}
}
//3. mapActions 的转换
methods: {
...mapActions("xx", [action1, action2]);
}
//4. mapActions 的展开
methods: {
action1(payload){
this.$store.dispatch("xx/action1", payload);
}
}
四、仓库模块的局部状态
首先要知道,做了仓库模块的拆分之后,getter与mutation中的第一个参数state是当前模块的局部state。 action中的第一个参数context。context中的state也是当前模块的局部state。 【注】有时我们需要在getter中action中获取到其余模块的state数据。
getter语法
getters:{
//state - 当前模块的state
//getter - 当前模块的getters
//rootState - 根模块的state数据。根据他就可以方便的去获取到其余模块的 state
getter1(state, getters, rootState){
}
}
action的语法
actions: {
//context 是一个对象,这个对象有一些属性
//state - 当前模块的局部 state
//getters - 当前模块的局部getters
//commit - 提交mutation的方法
//dispatch - 派发action的方法
//rootState - 根模块的state,根据他就可以方便的去获取到其余模块的state
action1(context, payload){
}
}
【注】!! mutation没有rootState这个东西。如果需要在mutation中使用其余模块的state数据的话,如何办?
传递payload即可。比如在action中获取到需要的rootState然后作为mutation的payload传递过去!。
五、v-model 绑定仓库中的数据的情况
问题现象:在input中输入的时候,会报错,也没有引起仓库数据的变化。 问题原因:根本原因是 仓库的state数据不允许直接去修改。并且拿数据的时候是用computed取出的。 解决:1. 仓库中需要提供一个mutation来处理变化。
2. 组件中给对应的computed提供一个getter和setter
PS:仓库的state数据不允许修改这只是一个规定。如果你主动去修改的话,并不会报错。但是不推荐。(直接修改是可以的,但是在时间旅行部分没办法操作。)【注】严格模式下会报错。 为了更好的处理报错情况,所以state数据都是映射到组件的computed上。 ?思考:描述一下为什么仓库数据需要在组件中使用computed来处理?