Vue 复学 之 状态管理 Vuex

news2024/11/24 20:51:06

Vuex是vue中的一种状态管理模式,就是一个 状态仓库,仓库做什么?存储状态、管理状态(数据)的变化、提供状态获取窗口。

本文中一些测试用例基于@vue/composition-api@1.7.1 , vuex@3.6.2, vue@2.6.10 做的验证。 Vue3 和 vuex@4.x 用法有所不同。

用来干什么,能做什么用?

可用于全局数据存储,跨层级组件通讯,动态路由。

在通讯的关键是,一方通知后,另一方怎么知晓。在vue2中利用 mapMutations, mapActions 解析出来,则可直接使用解析后的方法进行通知,另外一方 根据 mapGetters, mapState 解析出来的 属性、方法做接收,达到互通目的。

大体剖析

大致理解如下图:

1.Vuex 的 install 对Vue提供use 接入, 利用Vuex.Store 产生实例化对象,具体实例化的规则通过配置的 state, getters, mutations, actions,namespaced 确定。

2.mutations对应及时同步更新仓库数据,对应 store实例的.commit方法

3.actions 对应异步延时更新数据,对应store实例 的.dispatch方法。

4.commit 和 dispatch 函数所带参数,可以是指定type属性的对象,也可以利用参数1直接type类型。 ({type: "mutations中的项目", payload}) 或者 ("actions中的项目")

5. 关于响应式,vue2 直接用 mapState, mapGetter。 compositon-api 中可以直接使用 store示例对象下的 { 变量 } = toRefs(store.state)

6. 针对有命名空间模块,采用 “命名空间名(modules下挂接的属性名)/ ” 进行使用。

6.支持常量类型。为了让大家都清楚,提供了哪些mutation,action, 独立一个 _types ,在types中定义好类型名字,做store 的配置时,直接使用 [_types.XXX]

7. 针对state\ 非函数式getter,数据会进行缓存。

针对Vue3 组合式,对应Vuex4.x 版本, 其使用方式方法有所不同, 产生 store 用CreateStore, 示例使用 app.use(store),不是属性挂接,使用 useStore。

以前觉得vuex的使用必须按常规挂到主 Vue示例上,其实是着相了。 不管是 vuex 还是其他库、框架,本质都是基于某种语言实现的。vuex一样,我们常常使用 Vue.use(Vuex), 在 主Vue实例上挂接 {store: new Vuex.Store({state, getters, matutions, actions})}, 利用 $store 去访问。

那么既然都是js,是不是可以直接使用 store实例就好,答案是可以的,但在某些地方使用时会很不方便,比如vue2直接使用 mapXXX解析,为什么?因为Vuex中提供的映射 mapXXXX 函数内部采用的就是 this.$store 对象进行相关操作。

使用compostion-api时,直接引入 利用 store.js 中生成的 store 示例,不绑定到vue上,也可直接使用。

PS: Vue.use(Vuex) 不能省略,否则出现错误 must call Vue.use(Vuex) before creating a store instance.

具体用法 vue2 + vuex + compostion-api

针对 不采用 compositon-api 的,利用 mapXXX在对应属性上映射即可,方便快捷。

安装背负(Vue.use(Vuex)) -> 指腹为婚(new Vue({store: new Vuex.Store({}) })) -> 开支散叶 (...mapXXX)

直接访问比如

export default {
    computed: {
        ...mapState({
            // 箭头函数可使代码更简练
            count: state => state.count,
            // 传字符串参数 'count' 等同于 `state => state.count`
            countAlias: 'count',
            // 为了能够使用 `this` 获取局部状态,必须使用常规函数
            countPlusLocalState (state) {
              return state.count + this.localCount
            }
        }),
        ...mapGetters([
          'doneTodosCount',
          'anotherGetter',
        ])
    },
    methods: {
        ...mapMutations([
          'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
    
          // `mapMutations` 也支持载荷:
          'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
        ]),
        ...mapMutations({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
        }),
        ...mapActions({
          add: 'add' // 将 `this.add()` 映射为 `this.$store.dispatch('add')`
        })
     }
 }

不做映射 使用 this.$store 访问, 而composition-api 比较类似这种做法。

vue2 + vuex + compostion-api

基础使用过程:利用Vue.use(Vuex) 将vuex安装到vue上,背上vuex,开始vuex之旅。利用 new Vuex.Store() 创建 store 示例, 无需挂载到 Vue主示例的 store上。需要触发状态值维护的地方,直接 store.commit , store.dispatch 即可,需要 接收状态值的地方,使用 toRefs(store.state.模块) 的方式接收即可。

注意,如果要使用getter,取根级getter相对方便, store.getters.。 启用了命名空间的getter, 相对麻烦,可使用 store._wrappedGetters 获取,且都是函数式的。

代码如下:

store.js store生成文件

import Vue from "vue"
import Vuex from "vuex"
import app from "./modules/app"
import calc from "./modules/calc"

Vue.use(Vuex)  // 必须在 new Vuex.Store 之前

const store = new Vuex.Store({
    modules: {
        app,
        calc
    },
    // 这里启用了模块,注意:启用了模块管理于根root上配置不冲突
    state(){  // 用函数可以避免 污染
        return {}            
    },
    getters: {},
    mutations: {},
    actions: {}
})

export default store

app 模块配置.js

// 为方便 mutation  actions 的 外部使用,可使用 动态属性名 
const app = {
    // namespaced: true, // 启用命名空间后, getter 直接通过 store 实例对象是无法直接通过 store.getter获取到的
    state(){ // 状态
        return {
            count: 1
        }
    },
    getters: {
        getMoreUseAttr(state, getters){
            return state.count + 10
        },
        getMoreUseMethod: state => more => { // 函数式getter, 在使用时 函数调用
            return state.count + more
        }
    },
    mutations: { // 加工、维护。只能同步。 为方便 
        // 外部使用 .commit(mutationName, playload) 或者对象方式 {type, ...payload}
        increment (state, payload) {
            state.count += payload?.count
        }
    },
    actions: { // 行为。 异步维护。 
        // 第一个参数是store模块上下文 conctext,外部使用使用.dispatch(actionName, payload)或者({type: actionName, ...payload}) payload一般建议使用对象,可常量。
        addAsync({commit}, payload){
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    commit({type: "increment", ...payload})
                    resolve(payload)
                }, 2000)
            })
        }
    }
}

export default app

启用命名空间后, getter 直接通过 store 实例对象是无法直接通过 store.getter获取到的

calc 模块配置

const calc = {
    namespaced: true,
    state(){
        return {
            count: 2
        }
    },
    mutations: {
        increment(state, payload){ // 注意,这是与app配置中重名的。
            state.count += payload.count
        }
    },
    actions:{
        addAsync:{
            root: true, // 注意,这是与app配置中重名的。并提升到root根级
            handler(context, payload){
                new Promise((resolve, reject) => {
                    setTimeout(() => {
                        context.commit("increment", payload)
                    }, 1000)
                })
            }
        }
    }
}

export default calc

在启用命名空间的情况,mutation 或 action 也可使用 root: true 的方式提升到根级root上。

当多个模块 有重名mutation 或 actions 时, 如果启用命名空间,则互不关系,访问时指定命名空间,如果未启用命名空间或提升到了根级,在访问时,所有同名的都会被调用。

// 入口文件 main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

import store from "./components/store/index.js"

new Vue({
  render: function (h) { return h(App) },
  // store 不挂接
}).$mount('#app')

状态值维护组件:/components/vuex/index.vue

<template>
    <div>
        BusIndex
        <button @click="changeData">改变数据</button>
        <button @click="asynChangeData">异步改变</button>
        <div>
            <button>获取更大值</button>
            更大值 {{more}}
        </div>
    </div>
</template>

<script>
import {onMounted, ref, computed, getCurrentInstance} from "@vue/composition-api"
import store from "./store/store.js"

export default {
    name: "VuexIndex",
    setup(props, ctx){
        const changeData = () => {
            store.commit("increment", {count: 2})
            store.commit("calc/increment", {count: 5})
        }

        const asynChangeData = () => {
            store.dispatch("addAsync", {count: 10}, { root: true })
        }
        
        // 访问根级的getMoreUseAttr
        const more = computed(() => store.getters.getMoreUseAttr)

        return {
            changeData, asynChangeData, asynChangePowerData, more
        }
    }
}
</script>

状态值接收组件 /components/vuex/comp1.vue

<template>
    <div>
        状态值 app.count: {{count}} calc.count: {{count1}}
    </div>
</template>

<script>
import {onMounted, ref, toRefs} from "@vue/composition-api"
import store from "./store/store.js"

export default {
    name: "BusComp1",
    setup(props, ctx){
        const st = store 
        const {count} = toRefs(st.state.app)
        const {count: count1} = toRefs(st.state.calc)

        return {
            count,
            count1
        }
    }
}
</script>

主容器组件App.vue

<template>
  <div id="app">
    <div>
      vuex 测试
      <vuexIndex></vuexIndex>
      <vuexcomp1></vuexcomp1>
    </div>
  </div>
</template>

<script>
import vuexIndex from "./components/vuex/index.vue"
import vuexcomp1 from  "./components/vuex/comp1.vue"

export default {
  name: 'App',
  components: {
    vuexIndex, vuexcomp1
  }
}
</script>

官网地址: Vuex 是什么? | Vuex

关键词回顾:(至此,可以回想下这些关键词是干啥用的)

vuex, store, state, mutations, actions, getters;

mapState, mapMutations, mapActions, mapGetters;

modules, namespaced,registerModule;

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/448770.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【unity实战】随机地下城生成1——随机生成地下城初稿(含源码)

先看看实现的最终效果 #用到的素材 https://download.csdn.net/download/qq_36303853/87712757 导入素材 导入房间图片素材,配置图片信息信息 点击sprite Editor,开始切割图片 随机创建基本房间 已一个白底图片模拟房间预设体 思路:建立一个空的 GameObject 用来做…

C++中的STL容器

文章目录 一、序列式容器1.vector2.array3.deque4.list5.forward_list 二、关联式容器1.set、multiset、unordered_set和unordered_multiset2.map、multimap、unordered_map和unordered_multimap STL中的容器将一些应用最为广泛的数据结构实现了出来&#xff0c;它主要分为序列…

使用python下载wallpaper Engine订阅的壁纸/视频

一、为什么想下载wallpaper Engine的壁纸 在游戏平台steam上&#xff0c;有一个壁纸软件wallpaper Engine&#xff0c;人称小红车&#xff0c;里面有各种好看的动态壁纸和视频&#xff0c;可以给我们的电脑设置动态桌面&#xff0c;非常好用。   用过几次后&#xff0c;我有了…

Doris(14):索引

1 概念 索引用于帮助快速过滤或查找数据。 目前 Doris 主要支持两类索引&#xff1a; 内建的智能索引&#xff0c;包括前缀索引和ZoneMap索引用户创建的二级索引&#xff0c;包括Bloom Filter索引和Bitmap倒排索引。 前缀索引&#xff1a;即在排序的基础上&#xff0c;实现的…

kv server(配置以及性能测试)

首先在 Cargo.toml 里添加 serde 和 toml。我们计划使用 toml 做配置文件&#xff0c;serde 用来处理配置的序列化和反序列化&#xff1a; [dependencies] ... serde { version "1", features ["derive"] } # 序列化/反序列化 ... toml "0.5"…

antd表格a-table滚动失效。x轴滚动失效

目录 antd表格a-table滚动失效。x轴滚动失效 页面html代码如下。实现左右布局&#xff0c;左边侧边栏固定宽度&#xff0c;右边沾满剩余宽度 解决方案&#xff1a;在计算右侧宽度时&#xff0c;左边侧边栏固定宽度&#xff0c;右边沾满剩余宽度 情况1&#xff1a;左侧侧边栏…

第八章 查询和检索:Query DSL

版权声明 本文为Elastic开源社区版权所有,保证独立性和原创性,未获得授权和允许,任何组织和个人不得以任何方式传播或复制或分享。否则必将追究法律责任。 知识内容输出不易,请尊重他人劳动成果。严禁随意传播、复制和盗用他人成果或文章内容用以商业或盈利目的! 1、查询…

5.4 龙贝格算法

为什么有龙贝格算法&#xff1a; 龙贝格算法是一种数值积分方法&#xff0c;用于计算定积分的数值近似值。它是基于复合梯形法和复合辛普森法的推广和拓展&#xff0c;可以达到更高的精度。相较于复合梯形法和复合辛普森法&#xff0c;龙贝格算法的收敛速度更快&#xff0c;且…

nerfstudio介绍及在windows上的配置、使用

nerfstudio提供了一个简单的API&#xff0c;可以简化创建、训练和可视化NeRF的端到端过程。该库通过模块化每个组件来支持可解释的NeRF实现。nerfstudio源码地址: https://github.com/nerfstudio-project/nerfstudio , 通过模块化集成了多个NeRF扩展的实现&#xff0c;持续更新…

JUC-多线程(12. AQS)学习笔记

文章目录 1. 可重入锁1.1. 概述1.2. 可重入锁类型1.3. Synchronized 可重入实现机理 2. LockSupport2.1. LockSupport 是什么2.2. 3种线程等待唤醒的方法2.2.1 Object 的等待与唤醒2.2.2. Condition接口中的等待与唤醒2.2.3. 传统的 synchronized 和 Lock 实现等待唤醒通知的约…

C/C++开发,opencv读写图像与视频

目录 一、opencv的图像缓存表达&#xff08;cv::mat&#xff09; 二、图片读写 2.1 图片读写API 2.2 图片读写案例 2.3 案例编译与测试 三、opencv的视频读写&#xff1a; 3.1 视频读写接口 3.2 视频读写案例 3.3 编译与测试 一、opencv的图像缓存表达&#xff08;cv::mat&am…

2023网络搭建项目改革

好久没更新了&#xff0c;哈哈哈&#xff0c;也废话不多说&#xff0c;直接进入正题。 3月的时候就有人吓我说什么网搭取消了&#xff0c;当时我还觉得高兴&#xff0c;主要是不喜欢这个行业&#xff0c;要是没了我就可以跑路了&#xff0c;哈哈&#xff0c;然后我就觉得很奇怪…

【嵌入式系统与入门】Day02 Arduino 按键、蜂鸣器与湿温度传感器

文章目录 1. 按键控制1.1 认识按键1.2 工作原理1.3 Arduino代码展示1.4 原理图1.5 实现去抖【消抖动延时】 2. 蜂鸣器控制2.1 认识蜂鸣器2.2 分类2.3 工作原理2.4 连线2.5 Arduino代码展示 3. PWM模拟量输出3.2 Arduino代码展示 4. 湿温度测量4.1 认识器件4.2 传感器接口4.3 Ar…

CMU-自主探索导航系统(TARE FAR Planner)学习-All in one

参考引用 Autonomous Exploration Development EnvironmentTARE机器人自主导航系统社区-CSDN社区云TARE机器人自主导航系统公开课1TARE机器人自主导航系统公开课2CMU团队开发的全套开源自主导航算法FAR Planner —— IROS2022 最佳学生论文&#xff1c;论文阅读&#xff1e;TAR…

【源码分析】XXL-JOB的执行器的注册流程

目的&#xff1a;分析xxl-job执行器的注册过程 流程&#xff1a; 获取执行器中所有被注解(xxlJjob)修饰的handler执行器注册过程执行器中任务执行过程 版本&#xff1a;xxl-job 2.3.1 建议&#xff1a;下载xxl-job源码&#xff0c;按流程图debug调试&#xff0c;看堆栈信息…

【ONE·C++ || stack queue (一)】

总言 主要介绍栈和队列的基本函数使用&#xff1a;栈和队列、优先级队列、适配器、反向迭代器。 文章目录 总言1、栈和队列接口基本介绍1.1、基本介绍1.2、相关例题1.2.1、最小栈1.2.2、栈的压入、弹出序列1.2.3、逆波兰表达式求值 2、适配器介绍2.1、引入&#xff1a;如何实现…

儿童用灯哪个品牌好?分享五款儿童护眼台灯品牌

家中有小朋友上了幼儿园就已经戴上了眼镜&#xff0c;太让人心疼了 近视已经成为世界难题&#xff0c;而我国儿童近视形式尤为严峻 据官方数据显示&#xff0c;我国儿童青少年总体近视率竟高达52.7% 如何保护孩子眼睛&#xff0c;儿童用灯哪个品牌好&#xff1f; 那今天&am…

Open vSwitch 入门实践(8) VXLAN实验

目录 什么是VXLAN&#xff1f; VXLAN解决了什么问题&#xff1f; VXLAN网络如何工作&#xff1f; 简单VXLAN实验 主机A 主机B 测试 什么是VXLAN&#xff1f; VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;&#xff0…

Spring依赖注入 - Resource注解详解及与Autowired注解区别

上篇博客我们讲了Spring中的自动注入(byName,byType)和Autowired注解的工作原理以及源码分析&#xff0c;那么这次&#xff0c;我们来分析还没讲完的&#xff0c;剩下的核心的方法&#xff1a; Nullable Object resolveDependency(DependencyDescriptor descriptor, Nullable …

0.96寸OLED液晶显示器

在日常的小项目制作中我们经常会接触到OLED液晶显示器&#xff0c;本文介绍0.96寸液晶显示器的基本原理&#xff0c;辅助我们后续的小项目开发 OLED被称为有机激光二极管&#xff0c;也被称为有机激光显示&#xff0c;OLED采用有机材料涂层和玻璃基板&#xff0c;当有电流通过…