美文网首页Vue
Vuex基本使用

Vuex基本使用

作者: h2coder | 来源:发表于2023-08-20 17:56 被阅读0次

依赖版本

  • vue:2.6.14
  • vuex:3.6.2

配置Vuex

  • Vuex主要有5个配置部分,分别为
    • state,状态,也就是要共享的数据
    • mutations,同步修改state状态的函数
    • actions,异步修改state状态的函数,其实就是异步结束后,调用mutations的函数,实现修改state数据
    • getters,类似Vue组件的计算属性,可以对state状态数据进行统计、合并多个state为一个新的响应式变量
    • modules,模块,Vuex支持定义模块,每个模块都有自己的state、mutations、actions、getters

创建Vuex实例(store\index.js)

// Vuex相关配置,注意:Vue2的Vuex版本是3版本
import Vue from 'vue';
import Vuex from 'vuex';

// 注册Vuex插件
Vue.use(Vuex);

// 创建仓库,管理数据
const store = new Vuex.Store({
    // 严格模式,不能直接修改state的数据
    // 默认为false,是可以直接修改的,但我们都要遵循单向数据流,不允许组件中直接修改状态,设置为true,如果直接修改数据,就会报错!!
    strict: true,
    // 状态,存放数据
    state: {
    },
    // 同步修改state的函数,要求修改state,必须通过 mutation 函数
    mutations: {
    },
    actions: {
        // 异步修改数据,异步修改数据必须通过调用 mutation 函数,也就是在 mutation 上套了一层action
    },
    getters: {
        // 类似计算属性,通过计算某个state,或处理多个state属性来得到一个结果
    },
    // 模块
    modules: {
    }
});

// 默认导出
export default store

使用Vuex(main.js)

import Vue from 'vue'
import App from './App.vue'

// 导入Vuex的仓库实例
// import store from './store/index.js' // 完整路径写法
// import store from './store/index'// js后缀可以省略
import store from './store' // 如果js文件的名称为index,index 也可以省略

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  // 挂载到 Vue 的实例上,以后就可以通过Vue的实例,通过 $store 获取到仓库的实例
  store
}).$mount('#app')

开始使用

3种获取Vuex实例的方式

  • 在state中,定义状态变量
const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        uname: '万大爷'
    },
});

在Vue组件模板中

<div>
    {{ $store.state.uname }}
</div>

在Vue组件的js脚本中

export default {
name: 'App',
components: {
    HelloWorld
},
created() {
    console.log(this.$store)
    // 通过Vue实例上$store,适合在Vue组件的环境下使用
    console.log(this.$store.state.uname)
}

在单独的js文件中

// 单独引入store,适合在非Vue组件环境下的时候使用,例如在 xx.js 中
import store from '@/store'

console.log(store.state.uname);

辅助函数

我们在vuex的state、mutations、actions、getters中,配置变量和函数,都在vuex的JS对象里面,想要获取某个变量或函数,需要一层层调用去取,非常麻烦。

所以vuex提供了4个辅助映射函数,将state、getters的状态变量,映射到组件的计算属性中,将mutations、actions的函数映射到组件的函数中,方便我们通过this.变量名this.函数名来调用

  • mapState:映射state的辅助函数,将vuex中state的数据,映射到 computed 计算属性中
  • mapMutations:映射mutation的辅助函数,映射到 methods 中
  • mapActions:映射action的辅助函数,映射到 methods 中
  • mapGetters:映射getters的辅助函数,映射到 computed 计算属性中

核心概念 - state

state,状态,也就是数据,需要多个组件之间共享的数据

简单使用

  • 在state中,定义状态变量
const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        uname: '万大爷',
        count: 100,
    },
});
  • 在页面中,通过插值表达式使用状态变量
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 直接使用store实例,写起来太繁琐 -->
      uname:{{ $store.state.uname }} count:{{ $store.state.count }}
    </div>
  </div>
</template>

优化,使用辅助映射函数

  • vuex提供了辅助映射函数,来帮助我们将state状态数据,映射到vue组件的computed计算属性中,然后我们就可以直接使用,就不需要繁琐的使用$store.state.属性名来访问状态变量了
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 通过计算属性,获取状态数据 -->
      uname:{{ uname }} count:{{ count }}
    </div>
  </div>
</template>

<script>
// mapState:映射state的辅助函数,将vuex中state的数据,映射到 computed 计算属性中
import { mapState } from "vuex";

export default {
    computed: {
        ...mapState(["uname", "count"]),
    }
}
</script>

核心概念 - mutations

  • mutations,用来定义同步修改state状态的函数,在mutations中定义的函数,vuex调用时会传入2个参数
  • 参数一:state状态,就是vuex的state状态对象
  • 参数二:playload载荷,也就是参数,提交 mutation 时,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)

注意:不能直接修改state中的值,例如$store.state.count++,默认情况下,vuex是允许这样修改数据的,但vuex不推荐这样做,应该遵循单向数据流,数据在vuex中,修改数据应该通过vuex的mutations或actions去修改,而不应该在子组件中直接修改,否则会导致排错困难

如果想vuex阻止在组件中,直接修改state,可以在vuex的Vuex.Store构造函数,传入的配置对象中,配置strict属性,设置为true,就可以在直接修改时,报错

简单使用

  • 定义mutation函数
const store = new Vuex.Store({
    // 同步修改state的函数,要求修改state,必须通过 mutation 函数
    // 参数一:state状态,就是vuex的state状态对象
    // 参数二:playload载荷,也就是参数,提交 mutation 时,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)
    mutations: {
        // 添加数量
        addCount(state, playload) {
            state.count += playload.num
        },
        // 更新数量,为指定数量
        updateCount(state, count) {
            state.count = count
        }
    },
});
  • 在按钮点击事件中,调用mutation函数
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 违反vuex的单向数据流的原则,不要这样做 -->
      <button @click="$store.state.count++">(错误)直接修改,count数据</button>
      
      <br />
      
      <!-- 修改state中的数据,要通过调用mutations中的函数来实现 -->
      <button @click="fn1">(正确)通过mutations,修改count数据</button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn1() {
      // commit(),提交函数的参数,是 mutations 中要执行的函数名
      this.$store.commit("addCount")
      
      // 传递参数,注意只能传一个参数,多个参数要用对象或数组包裹
      this.$store.commit("addCount", {
        num: 100,
        num2: 200,
      });
    },
  }
}
</script>

优化,使用辅助映射函数

  • mapState类似,对于mutation,vuex也提供了mapMutations函数,用来映射mutations中的函数到methods方法中
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 违反vuex的单向数据流的原则,不要这样做 -->
      <button @click="$store.state.count++">(错误)直接修改,count数据</button>
      
      <br />
      
      <!-- 修改state中的数据,要通过调用mutations中的函数来实现 -->
      <button @click="fn1">(正确)通过mutations,修改count数据</button>
    </div>
  </div>
</template>

<script>
// mapMutations:映射mutation的辅助函数,映射到 methods 中
import { mapMutations } from "vuex";

export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn1() {
      // commit(),提交函数的参数,是 mutations 中要执行的函数名
      // this.$store.commit("addCount")
      // 传递参数,注意只能传一个参数,多个参数要用对象或数组包裹
      // this.$store.commit("addCount", {
      //   num: 100,
      //   num2: 200,
      // });

      // 调用 mapMutations 映射后的函数
      this.addCount({
        num: 100,
        num2: 200,
      });
    },
    // 映射mutations中的函数,到methods中,然后就可以通过 this.addCount() 来调用 mutations 中的函数
     ...mapMutations(["addCount"]),
   }
}
</script>

核心概念 - actions

  • actions,定义异步修改state的函数,底层也是通过提交mutation来实现修改state
  • actions中的函数,vuex调用时,都会传2个参数
    • 参数一:context上下文,能获取到store身上的哪些属性和方法
    • 参数二,参数,派发 action 时,传的参数,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)

简单使用

  • 定义action函数
const store = new Vuex.Store({
    actions: {
        // 异步修改数据,异步修改数据必须通过调用 mutation 函数,也就是在 mutation 上套了一层action
        // 参数一:context上下文,能获取到store身上的哪些属性和方法
        // 参数二,参数,派发 action 时,传的参数,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)
        updateAsyncCount(context, num) {
            setTimeout(() => {
                // 修改数据,提交mutation,同步修改数据
                context.commit("updateCount", num)
                console.log(`异步修改数据成功,新值为${num}`);
            }, 1000);
        }
    },
});
  • 在按钮点击事件中,派发action函数
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <button @click="fn2">异步,修改数据</button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn2() {
      // 异步修改数据,触发action函数
      // dispatch(),派发函数的参数,是 actions 中要执行的函数名
      // 传递参数,同样也是智能传递一个参数,多个参数要用对象或数组包裹
      this.$store.dispatch("updateAsyncCount", 888)
    },
  }
}
</script>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <button @click="fn2">异步,修改数据</button>
    </div>
  </div>
</template>

<script>
// mapActions:映射action的辅助函数,映射到 methods 中
import { mapActions } from "vuex";

export default {
  methods: {
    fn2() {
      // 调用 mapActions 映射后的函数
      this.updateAsyncCount(888);
    },
    // 映射actions中的函数,到methods中,然后就可以通过this.updateAsyncCount() 来调用 actions 中的函数
     ...mapActions(["updateAsyncCount"]),
   }
}
</script>

核心概念 - getters

  • 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters
  • getters类似vue组件中的计算属性

基本使用

  • 在state中,定义状态变量和getters
  • getters中,定义total函数,计算状态变量list的值,得出一个总数,作为该函数的返回值
  • 使用方式:$store.getters.total,每次都要写$store.getters前缀,太繁琐
const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        list: [1, 2, 3, 4, 5, 6]
    },
    getters: {
        // 类似计算属性,通过计算某个state,或处理多个state属性来得到一个结果
        total(state) {
            return state.list.reduce((prev, current) => {
                return prev + current
            }, 0)
        }
    },
});
  • 在页面中,使用getters
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 使用vuex的getters属性 -->
      gettes属性:{{ $store.getters.total }}
    </div>
  </div>
</template>

<script>
    export default {
      name: "App",
      created() {
        // 获取 getters 属性,类似于计算属性
        console.log(this.$store.getters.total);
    }
</script>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 使用vuex的getters属性 -->
      gettes属性:{{ total }}
    </div>
  </div>
</template>

<script>
// mapGetters:映射getters的辅助函数,映射到 computed 计算属性中
import { mapGetters } from "vuex";

export default {
  computed: {
    // 映射vuex的getters属性
    ...mapGetters(["total"]),
   }
}
</script>

模块化

  • 由于 vuex 使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。(当项目变得越来越大的时候,Vuex会变得越来越难以维护)

创建和配置模块

  • 单独定义一个模块user.js,同样配置state、mutations、actions、getters
  • 并通过export default暴露出该模块,准备给vuex注册模块
  • 注意:namespaced属性,必须设置,否则调用时,会报错,说找不到该模块
// 用户模块的store
const state = () => ({
})

const getters = {
}

// 同步操作state数据
const mutations = {
}

// 异步操作state
const actions = {
}

export default {
    // 开启命名空间,这样 mapState、mapMutations、mapActions等辅助函数,才能使用该模块
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
  • 在vuex中,注册模块
// Vuex相关配置,注意:Vue2的Vuex版本是3版本
import Vue from 'vue';
import Vuex from 'vuex';

// 引入用户模块的store
import user from '@/store/modules/user'

// 注册Vuex插件
Vue.use(Vuex);

// 创建仓库,管理数据
const store = new Vuex.Store({
    ...省略其他配置
    
    // 模块
    modules: {
      // 模块名:模块对象
      // user: user
      user
    }
});

// 默认导出
export default store

使用方式的变化

准备数据

// 用户模块的store
const state = () => ({
    userInfo: {
        name: 'zs',
        age: 18
    },
    num: 100
})

const getters = {
    // 返回格式化年龄的字符串
    age(state) {
        return state.num + '岁'
    },
}

// 同步操作state数据
const mutations = {
    // 修改 num 数据
    updateNum(state) {
        state.num++
    }
}

// 异步操作state
const actions = {
    updateAsyncNum(context) {
        // 1秒后,提交mutation,更新state
        setTimeout(() => {
            context.commit("updateNum")
        }, 1000);
    }
}

export default {
    // 开启命名空间,这样 mapState、mapMutations、mapActions等辅助函数,才能使用该模块
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

关于state

使用模块后,之前的使用方式都需要加上模块名

  • 普通方式获取,例如
    • 未使用模块:$store.state.属性名
    • 使用模块:$store.state.模块名.属性名
  • 使用mapState辅助映射函数
    • 未使用模块:...mapState(["属性名"])
    • 使用模块:...mapState("模块名", ["属性名"])
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 模块数据,直接获取,太繁琐 -->
      用户模块-name:{{ $store.state.user.userInfo.name }} 用户模块-age:{{
        $store.state.user.userInfo.age
      }}
      
      <br />

      <!-- 模块数据,使用mapState辅助函数 -->
      用户模块-name:{{ userInfo.name }} 用户模块-age:{{ userInfo.age }}
    </div>
  </div>
</template>

<script>
// mapState:映射state的辅助函数,将vuex中state的数据,映射到 computed 计算属性中
import { mapState } from "vuex";

export default {
  created() {
    console.log(this.$store.state.user);
    console.log(this.$store.state.user.userInfo.name);
    console.log(this.$store.state.user.userInfo.age);
  },
  computed: {
    // 映射vuex的state属性
    ...mapState("user", ["userInfo", "num"]),
   }
}
</script>

关于mutations

使用模块后,之前的使用方式都需要加上模块名

  • 普通方式获取,例如
    • 未使用模块:this.$store.commit("函数名")
    • 使用模块:this.$store.commit("模块名/函数名")
  • 使用mapMutations辅助映射函数
    • 未使用模块:...mapMutations(["函数名"])
    • 使用模块:...mapMutations("模块名", ["函数名"])
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      user模块的mutation:<button @click="fn3">{{ num }}</button>
    </div>
  </div>
</template>

<script>
// mapMutations:映射mutation的辅助函数,映射到 methods 中
import { mapMutations } from "vuex";

export default {
  methods: {
    fn3() {
      // 调用user模块的mutation函数,格式:模块名/函数名
      this.$store.commit("user/updateNum");
      
      // 使用mapMutations辅助函数,映射后mutation函数
      this.updateNum();
    },
    // 映射user模块的mutation函数
    ...mapMutations("user", ["updateNum"]),
  }
}
</script>

关于actions

使用模块后,之前的使用方式都需要加上模块名

  • 普通方式获取,例如
    • 未使用模块:this.$store.dispatch("函数名")
    • 使用模块:this.$store.dispatch("模块名/函数名")
  • 使用mapMutations辅助映射函数
    • 未使用模块:...mapActions(["函数名"])
    • 使用模块:...mapActions("模块名", ["函数名"])
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      user模块的action:<button @click="fn4">{{ num }}</button>
    </div>
  </div>
</template>

<script>
// mapActions:映射action的辅助函数,映射到 methods 中
import { mapActions } from "vuex";

export default {
  methods: {
    fn4() {
      // 调用user模块的action函数,格式:模块名/函数名
      this.$store.dispatch("user/updateAsyncNum")

      // 使用mapActions辅助函数,映射后的action函数
      this.updateAsyncNum();
    },
    // 映射user模块的action模块
    ...mapActions("user", ["updateAsyncNum"]),
  }
}
</script>

关于getters

使用模块后,之前的使用方式都需要加上模块名

  • 普通方式获取,例如
    • 未使用模块:$store.getters.属性名
    • 使用模块:$store.getters.[模块名/属性名]
  • 使用mapState辅助映射函数
    • 未使用模块:...mapGetters(["属性名"])
    • 使用模块:...mapGetters("模块名", ["属性名"])

注意:getters和state虽然都是类似属性的变量,但是在加入模块后,写法是有区别的,例如

  • state是:$store.state.模块名.属性名
  • getters是:$store.getters['模块名/属性名']
  • 错误写法:$store.getters.模块名.属性名

可以看见,getters没有像state那样,在getters下再新建一个模块名的对象,而是在属性名的基础上增加模块和斜杠。那么在JS中,就必须使用中括号来访问了,也就是$store.getters['user/age'],而不能是$store.getters.'user/age',因为这是不合法的

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 直接使用user模块的getter属性,太繁琐 -->
      user模块的getters:<span>年龄 {{ $store.getters['user/age'] }}</span>
      <br>
      <!-- 使用mapGetters辅助函数,映射的getter属性 -->
      user模块的getters:<span>年龄 {{ age }}</span>
    </div>
  </div>
</template>

<script>
// mapGetters:映射getters的辅助函数,映射到 computed 计算属性中
import { mapGetters } from "vuex";

export default {
  created() {
    // 获取user模块的getter属性
    console.log(this.$store.getters['user/age']);
  },
  computed: {
    // user模块中的getter
    ...mapGetters('user', ['age'])
  }
}
</script>

相关文章

  • Vuex

    1.Vuex概述 2.Vuex基本使用 3.使用Vuex完成todo案例 1.Vuex概述 Vuex是实现组件全局...

  • vuex@2.x 文档

    1、https://vuex.vuejs.org/zh-cn/2、vuex 使用文档3、vuex2.0 基本使用(...

  • VUEX基本介绍,包含实战示例及代码(基于Vue2.X)

    VUEX 1 VUEX基本介绍 1.1 官方API 1.2 什么是vuex 1.3 Vuex使用场景 1、Vuex...

  • 在vue中使用typescript - 使用篇

    基本使用 在vuex中使用 注: typescript目前对vuex的支持还不完善,需要引入 vuex-class...

  • vuex基本使用

    vuex使用 1、安装vuex 2、安装promise: Vuex 依赖 Promise。如果你支持的浏览器并没有...

  • Vuex基本使用

    vuex实现原理 1.在store.js中设置数据 2.在页面中发送数据 3.在store.js中接收从页面发送过...

  • VUEX

    目标 能够说出VUEX的基本使用步骤 能够说出vuex的核心概念 能够基于vuex实现业务功能 目录 vuex概述...

  • Vuex的基本使用

    1.安装Vuex 2.创建store.js文件,在main.js中导入并配置store选项 3.编辑store.j...

  • Vuex-基本使用

    引用 在一个模块化的打包系统中,您必须显式地通过 Vue.use() 来安装 Vuex: 当使用全局 script...

  • vuex - 基本使用 -- getter

    有的组件中获取到 store 中的state, 需要对进行加工才能使用,computed 属性中就需要写操作函数...

网友评论

    本文标题:Vuex基本使用

    本文链接:https://www.haomeiwen.com/subject/jqasmdtx.html