当前位置: 首页 > news >正文

【手写 Vuex 源码】第八篇 - Vuex 的 State 状态安装

一,前言

上一篇,主要介绍了 Vuex 模块安装的实现,针对 action、mutation、getter 的收集与处理,主要涉及以下几个点:

  • Vuex 模块安装的逻辑;
  • Vuex 代码优化;
  • Vuex 模块安装的实现;
  • Vuex 初始化流程梳理;

本篇,继续介绍 Vuex 模块相关概念:Vuex 的 State 状态安装;


二,前文梳理

  • 前面,通过依赖收集对 options 的格式化处理得到了“模块树”;
  • 又通过依赖安装对“模块树”进行递归操作:从根模块开始,将对应的 getter、mutation、action 统一放入 Store 类的 this._actions、this._mutations、this._wrappedGetters 中;

Vuex 的初始化流程如下:

  • 当项目引用并注册 vuex 插件时,即 Vuex.use(vuex),将执行 Vuex 插件中的 install 方法;
  • install 方法,接收外部传入的 Vue 实例,并通过 Vue.mixin 实现 store 实例的全局共享;
  • 项目中通过 new Vuex.Store(options) 配置 vuex 并完成 store 状态实例的初始化;
  • 在 Store 实例化阶段时,将会对 options 选项进行处理,此时完成 Vuex 模块收集和安装操作;
  • new Vue 初始化时,将 store 实例注入到 vue 根实例中(此时的 store 实例已实现全局共享);

接下来,继续在 installModule 方法中处理“模块树”的 State 状态;


三,Vuex 模块安装-State状态安装

1,State 状态的安装逻辑

对“模块树”中状态的安装,就是将所有子模块上的 State 状态,挂载到对应父模块的 State 状态上;

  • 处理范围:子模块,即 path.length > 0时,执行状态安装逻辑;
  • 处理逻辑:将子模块的状态 module.state,挂载到其父模块的状态上;

2,引出问题

所以,首先需要解决以下两个问题:

  • 问题 1:如何找到当前子模块对应的父模块?
  • 问题 2:如何将子模块状态挂载到父模块的状态上?

3,问题 1:如何找到当前子模块对应的父模块?

从“模块树”中,查找一个子模块对应的父模块,这个逻辑其实在模块收集时就已经写过了:

/*** 安装模块* @param {*} store       容器* @param {*} rootState   根状态* @param {*} path        所有路径* @param {*} module      格式化后的模块对象*/
const installModule = (store, rootState, path, module) => {// 处理子模块:将子模块上的状态,添加到对应父模块的状态中;if(path.length > 0){// 从根状态开始逐层差找,找到当前子模块对应的父模块状态let parent = path.slice(0, -1).reduce((memo, current)=>{return memo[current]}, rootState)}
}

接下来,只需要向这个 parent 父模块的 State 状态中,添加当前子模块状态即可;

4,问题 2:如何将子模块状态挂载到父模块的状态上?

  • 子模块状态:module.state;
  • 父模块状态:parent;

那么,直接向父模块状态中添加子模块状态就可以了吗?

parent[path[path.length-1]] = module.state;

右侧的进度条告诉我们不会这么简单的:

  • 在 Vuex 中,模块是可以动态进行添加的;
  • 在 Vuex 中,状态应该是响应式的;

因此,我们希望动态添加的模块也是响应式的数据;

如果,直接向对象中添加一个不存在的属性,是无法被声明为响应式数据的;

所以,需要通过 Vue.set API 向父模块状态中添加子模块状态,以此实现对象新增属性为响应式数据;

这样,当 Vuex 动态注册模块时,新添加的状态属性就是响应式数据了;

备注:

  • 如果使用 Vue.set 向一个非响应式对象添加属性,相当于直接为普通对象添加属性并赋值;
  • 此时,即 resetStoreVM 方法执行前,parent就是一个普通对象,当 resetStoreVM 方法执行完成后,才是响应式数据,因此,使用 Vue.set在两种状态下都是兼容的;

5,代码实现

从根模块开始递归处理,将当前子模块状态定义到其对应父模块状态上:

  • 从根模块的状态开始找,返回当前模块所属的父模块 parent;
  • 将当前模块的 State 状态设置到父模块 parent 的 path[path.length-1] 属性中;
    即:将所有状态都设置到 rootState 上:
// src/vuex/store.js#installModuleconst installModule = (store, rootState, path, module) => {// 处理子模块:将子模块上的状态,添加到对应父模块的状态中;if(path.length > 0){// 从根状态开始逐层差找,找到当前子模块对应的父模块状态let parent = path.slice(0, -1).reduce((memo, current)=>{return memo[current]}, rootState)// 支持 Vuex 动态添加模块,将新增状态直接定义成为响应式数据;Vue.set(parent, path[path.length-1], module.state);}
}

6,执行情况分析

  • 首次进入 installModule 方法,由于 path = [],不会进入状态安装逻辑;此时,会遍历根模块中的 actionsmutationsgetters 分别放到 store 实例中的 _actions_mutations_wrappedGetters 中;最后,通过当前模块 module.forEachChild 递归遍历子模块(深度优先递归),递归的终止条件是当父模块下不存在子模块时;

    备注:在遍历处理当前模块下的子模块时,完成 path 路径的拼接操作;

  • 非首次进入 installModule 方法,此时 path.length > 0, 进行子模块状态安装:先通过 path 找到当前子模块对应的父模块状态对象,并通过Vue.set向其中添加子模块状态,该属性被直接定义为响应式数据;

打印状态安装完成后的state,此时 state 包含 Vuex 中全部模块的状态:

// src/vuex/store.jsexport class Store {constructor(options) {const state = options.state;// 收集所有模块中的action、mutation、getter 放到 Store 上this._actions = {};this._mutations = {};this._wrappedGetters = {};// 1,模块收集:options 格式化 -> Vuex 模块树this._modules = new ModuleCollection(options);console.log("格式化后的模块树对象", this._modules)// 2,模块安装:installModule(this, state, [], this._modules.root);console.log("模块安装结果:state", state)}
}

image.png

如上图所示:根模块状态中包含模块 A 和模块 B 的状态,模块 A 中包含模块 C 的状态;


四,结尾

本篇,主要介绍了 Vuex 的 State 状态安装,主要涉及以下几个点:

  • State 状态的安装逻辑;
  • 两个核心问题的思路;
  • 代码实现以及执行情况分析;

下一篇,继续介绍 Vuex 模块相关概念:Vuex 数据响应式的实现


维护日志

  • 20211008
    • 全篇重构,调整文章目录结构,添加核心逻辑分析;

相关文章:

【手写 Vuex 源码】第八篇 - Vuex 的 State 状态安装

一,前言 上一篇,主要介绍了 Vuex 模块安装的实现,针对 action、mutation、getter 的收集与处理,主要涉及以下几个点: Vuex 模块安装的逻辑;Vuex 代码优化;Vuex 模块安装的实现;Vue…...

Mac下拉式终端的安装与配置 (iTerm2)

Mac下拉式终端的安装与配置 使用效果如图所示 安装前置软件 iTerm2 很可惜,如此炫酷的功能在原终端中并不能实现,我们需要借助iTerm2这个软件来实现。 官网链接:iTerm2 - macOS Terminal Replacement 我们点击download下载即可 配置 当我…...

使用 Spring 框架结合阿里云 OSS 实现文件上传的代码示例

使用 Spring 框架结合阿里云 OSS 实现文件上传的代码示例POM文件配置文件上传工具类控制层使用yaml配置文件(第二种用法,看公司要求)注入 OSSClient 对象及工具类(第二种用法,看公司要求)使用 Vue 前端代码…...

神经网络基础知识

神经网络基础知识 文章目录神经网络基础知识一、人工神经网络1.激活函数sigmod函数Tanh函数Leaky Relu函数分析2.过拟合和欠拟合二、学习与感知机1.损失函数与代价函数2. 线性回归和逻辑回归3. 监督学习与无监督学习三、优化1.梯度下降法2.随机梯度下降法(SGD)3. 批量梯度下降法…...

SpringBoot开发规范部分通用模板+idea配置【项目通用-1】

SpringBoot开发规范通用模板 1 分页插件使用 通过MybatisPlus配置分页插件拦截器 Configuration MapperScan("com.xuecheng.content.mapper") //拦截的mapper层 public class MybatisPlusConfig {//定义分页的拦截器Beanpublic MybatisPlusInterceptor getMybatisPl…...

程序的机器级表示part3——算术和逻辑操作

目录 1.加载有效地址 2. 整数运算指令 2.1 INC 和 DEC 2.2 NEG 2.3 ADD、SUB 和 IMUL 3. 布尔指令 3.1 AND 3.2 OR 3.3 XOR 3.4 NOT 4. 移位操作 4.1 算术左移和逻辑左移 4.2 算术右移和逻辑右移 5. 特殊的算术操作 1.加载有效地址 指令效果描述leaq S, DD…...

基于YOLOV5的钢材缺陷检测

数据和源码见文末 1.任务概述 数据集使用的是东北大学收集的一个钢材缺陷检测数据集,需要检测出钢材表面的6种划痕。同时,数据集格式是VOC格式,需要进行转化,上传的源码中的数据集是经过转换格式的版本。 2.数据与标签配置方法 在数据集目录下,train文件夹下有训练集数据…...

Session与Cookie的区别(三)

中场休息 让我们先从比喻回到网络世界里,HTTP 是无状态的,所以每一个 Request 都是不相关的,就像是对小明来说每一位客人都是新的客人一样,他根本不知道谁是谁。 既然你没办法把他们关联,就代表状态这件事情也不存在。…...

七大设计原则之接口隔离原则应用

目录1 接口隔离原则介绍2 接口隔离原则应用1 接口隔离原则介绍 接口隔离原则(Interface Segregation Principle, ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口时…...

【Shell1】shell语法,ssh/build/scp/upgrade,环境变量,自动升级bmc

文章目录1.shell语法:shell是用C语言编写的程序,是用户使用Linux的桥梁,硬件>内核(os)>shell>文件系统1.1 变量:readonly定义只读变量,unset删除变量1.2 函数:shell脚本传递的参数中包含空格&…...

JavaScript HTML DOM - 改变CSS

JavaScript 是一种动态语言,它可以动态地修改网页的外观,并且使用HTML DOM(文档对象模型)可以更方便地控制HTML元素的样式。 JavaScript 通过在HTML DOM中更改CSS属性来更改样式,这些CSS属性包括颜色、位置、字体大小…...

mycat连接mysql 简单配置

mycat三个配置文件位于conf下 可通过Notepad操作 首先配置service.xml中的user标签&#xff0c;设置用户名&#xff0c;密码&#xff0c;查询权限&#xff0c;是否只读等 只是设置了root用户&#xff0c;有所有权限 配置schema.xml <?xml version"1.0"?&g…...

Spring常用注解

文章目录一、Bean交给Spring管理1、Component2、Bean3、Controller4、Service5、Repository6、Configuration7、ComponentScan二、作用域1、Lazy(false)Scope三、依赖注入1、Autowired2、Resource3、Qualifier四、读取配置文件值1、Value一、Bean交给Spring管理 1、Component …...

I.MX6ULL内核开发9:kobject-驱动的基石

目录 一、摘要 二、重点 三、驱动结构模型 四、关键函数分析 kobject_create_and_add()函数 kobject_create()函数 kobject_init&#xff08;&#xff09;函数 kobject_init_internal(&#xff09;函数 kobject_add&#xff08;&#xff09;函数 kobject_add_varg&am…...

Docker-harbor私有仓库

一、Harbor概述 1、Harbor的概念 • Harbor是VMware公司开源的企业级Docker Registry项目&#xff0c;其目标是帮助用户迅速搭建一个企业级的Docker Registry服务 • Harbor以 Docker 公司开源的Registry 为基础&#xff0c;提供了图形管理UI、基于角色的访问控制(Role Base…...

Java之动态规划之子序列问题

目录 0.动态规划问题 一.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 二.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 三.最长重复子数组 1.题目描述 2.问题分析 3.代码实现 4.代码的优化(滚动数组) 四.最长公共子序列 1.题目描述 2.问题分析 3.代…...

java ArrayList

目录 一.简单介绍 二.ArrayList的底层结构 2.1ArrayList的底层结构和操作分析 2.ArrayList 底层源码分析 三.ArrayList 方法 四.代码使用方法 一.简单介绍 ArrayList 类是一个可以动态修改的数组&#xff0c;与普通数组的区别就是它是没有固定大小的限制&#xff0c;我们…...

前端——周总结系列四

1 JS变量与常量 概述 变量&#xff1a;在后续编码过程中会被重新赋值&#xff0c;是不断变化的。常量&#xff1a;固定不变的数据&#xff0c;日常生活比如性别男&#xff0c;代码层面是在编码过程中不会变化的固定数据。 命名规则 变量 可以包含数字&#xff0c;字母&…...

Linux重定向符、管道符讲解

目录 重定向 将命令与文件进行互动 输出重定向 输入重定向 管道符 将命令与命令互动起来 重定向 将命令与文件进行互动 重定向分类 一般情况下&#xff0c;Linux命令运行时都会打开一下三个文件 标准输入文件&#xff1a;stdin文件&#xff0c;文件描述符为0&#xff0c;Li…...

【C++】多态

多态一、多态的概念及定义1.1 虚函数1.2 虚函数重写的特殊情况1.3 override 和 final二、抽象类2.1 概念2.2 用处三、多态的原理3.1 虚函数表3.1.1 虚函数与虚表的位置3.2 多态的原理3.3 静态绑定和动态绑定四、单/多继承的虚函数表4.1 单继承的虚函数表4.2 多继承的虚函数表一…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)

目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 ​编辑​编辑 UDP的特征 socke函数 bind函数 recvfrom函数&#xff08;接收函数&#xff09; sendto函数&#xff08;发送函数&#xff09; 五、网络编程之 UDP 用…...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...