vue3源码(二)reactiveeffect

一.reactive与effect功能

reactive方法会将对象变成proxy对象, effect中使用reactive对象时会进行依赖收集,稍后属性变化时会重新执行effect函数。

<div id="app"></div><script type="module">import {reactive,effect,} from "/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js";//   reactive创建一个响应式对象//   effect 副作用函数,默认执行一次,数据变化后再次执行const state = reactive({ name: "orange", age: 18 });effect(() => {document.getElementById("app").innerHTML = state.name;});console.log(state);setTimeout(() => {state.name = "apple";}, 2000);</script>

二.reactive与effect实现

1.实现reactive

1.1 get、set基础实现

// reactive.ts
import { isObject } from "@vue/shared";const mutableHandlers = {get(target, key, receiver) {return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {return Reflect.set(target, key, value, receiver);},
};export function reactive(target) {if (!isObject(target)) {return target;}const proxy = new Proxy(target, mutableHandlers);return proxy;
}

如下图,如果采用target[key]方法,获取aliasName时 不会触发nameget
在这里插入图片描述

1.2 完善重复

const state = { name: "orange", age: 18 };const p1 = reactive(state);const p2 = reactive(state);const p3 = reactive(p1);console.log(p1 === p2);console.log(p1 === p3);
  • 响应式数据缓存,防止重复代理
    使用mapkey为对象,值为响应式对象,实现p1 === p2
const reactiveMap = new WeakMap(); //内存泄漏
export function reactive(target) {if (!isObject(target)) {return target;}const exitProxy = reactiveMap.get(target);if (exitProxy) {return exitProxy;}const proxy = new Proxy(target, mutableHandlers);reactiveMap.set(target, proxy);return proxy;
}
  • 响应式数据标记
    用枚举做标记,响应式对象都有get和set方法,p1初次创建时state没有get和set方法,target[ReactiveFlags.IS_REACTIVE]取值为false,创建p3时,p1响应式,取值为true,直接返回p1
export const enum ReactiveFlags {IS_REACTIVE = "__v_isReactive",
}get(target, key, receiver) {if (ReactiveFlags.IS_REACTIVE == key) {return true;}return Reflect.get(target, key, receiver);},export function reactive(target) {...,if (target[ReactiveFlags.IS_REACTIVE]) {return target;}const proxy = new Proxy(target, mutableHandlers);reactiveMap.set(target, proxy);return proxy;
}

2.实现effect

2.1 effect函数

vue2vue3早期的依赖收集采用的都是栈方式存储,vue3后来改为树型数据存储。
effect执行时,把当前effect作为全局的,触发属性的get方法,收集依赖

let activeEffect;
class ReactiveEffect {public deps: Array<any> = []; // 判断依赖属性public active: boolean = true; // 是否激活public parent = undefined; constructor(public fn) {}run() {if (!this.active) {return this.fn();}try {this.parent = activeEffect;activeEffect = this;return this.fn();} finally {activeEffect = this.parent;this.parent = undefined;}}
}
export function effect(fn) {const _effect = new ReactiveEffect(fn);_effect.run();
}

2.2 依赖收集

执行effect时,会触发依赖属性的get方法,在属性的get中进行依赖收集

get(target, key, receiver) {if (ReactiveFlags.IS_REACTIVE == key) {return true;}console.log(activeEffect, key);track(target,key)return Reflect.get(target, key, receiver);},
/* 属性变动后 要重新执行run 需要把属性和effect关联起来 收集对象上属性关联的effect不能光记录属性,容易两个对象有重名的属性,所以需要带着对象记录target为对象let mapping = {target:{name:[effect1,effect2,effect3] 一个属性可以在多个页面使用}}*/
const targetMap = new WeakMap();
export function track(target, key) {// 如果取值操作没有发生在effect中,则不需要收集依赖if (!activeEffect) {return;}// 判断是否已经记录过let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {// 值为一个不重复数组depsMap.set(key, (dep = new Set()));}let shouldTrack = !dep.has(key);if (shouldTrack) {dep.add(activeEffect);activeEffect.deps.push(dep); //同时effect记住当前这个属性}
}

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

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

相关文章

从零学Java MySQL

MySQL 文章目录 MySQL初识数据库思考&#xff1a;1 什么是数据库&#xff1f;2 数据库管理系统 初识MySQLMySQL卸载MySQL安装1 配置环境变量2 MySQL目录结构及配置文件 连接MySQL数据库基本命令MySQL基本语法&#xff1a;1 查看MySQL服务器中所有数据库2 创建数据库3 查看数据库…

leetcode—课程表 拓扑排序

1 题目描述 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习课程 ai 则 必须 先学习课程 …

《WebKit 技术内幕》学习之五(2): HTML解释器和DOM 模型

2.HTML 解释器 2.1 解释过程 HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。 这一过程中&#xff0c;WebKit 内部对网页内容在各个阶段的结构表示。 WebKit 中这一过程如下&#xff1a;首先是字节流&#xff0c;经过解码之…

ORBSLAM3安装

0. C11 or C0x Compiler sudo apt-get install gccsudo apt-get install gsudo apt-get install build-essentialsudo apt-get install cmake1. 依赖 在该目录终端。 1. 1.Pangolin git clone https://github.com/stevenlovegrove/Pangolin.git sudo apt install libglew-d…

Python基础第九篇(Python可视化的开发)

文章目录 一、json数据格式&#xff08;1&#xff09;.转换案例代码&#xff08;2&#xff09;.读出结果 二、pyecharts模块介绍三、pyecharts模块入门&#xff08;1&#xff09;.pyecharts模块安装&#xff08;2&#xff09;.pyecharts模块操作&#xff08;1&#xff09;.代码…

C++力扣题目509--斐波那契数 70--爬楼梯 746--最小花费爬楼梯

509. 斐波那契数 力扣题目链接(opens new window) 斐波那契数&#xff0c;通常用 F(n) 表示&#xff0c;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n -…

了解WPF控件:PrintDialog常用属性与用法(八)

掌握WPF控件&#xff1a;熟练常用属性&#xff08;八&#xff09; PrintDialog -一个对话框&#xff0c;用于在打印文档时显示打印设置参数供用户选择并确认。通过该控件&#xff0c;用户可以选择打印机、打印的范围、打印的份数、打印质量等。 常用属性描述CurrentPageEnab…

制作编写使用说明书:在结构、风格与内容方面需要注意什么?

如今&#xff0c;一个清晰、简洁、易于理解的使用说明书不仅能够帮助用户正确地使用产品&#xff0c;还能提升用户体验并树立品牌形象。而制作编写一份优质的使用说明书需要我们在结构、风格与内容三个方面下功夫。那么在制作编写使用说明书时需要注意哪些关键要素呢&#xff1…

【JavaWeb】日程管理系统 项目搭建 第二期

文章目录 一、数据库准备二、导入依赖 与 JDBC工具类三、pojo包处理四、daodao包工具类 五、service六、controllerservlet 基类 反射 七、加密工具类 MD5八、页面文件九、业务代码9.1 注册业务处理9.2 登录业务处理 总结 一、数据库准备 创建数据库&#xff1a; SET NAMES …

骨传导耳机综评:透视南卡、韶音和墨觉三大品牌的性能与特点

在当前的蓝牙音频设备领域中&#xff0c;骨传导蓝牙运动耳机以其出色的安全特性和舒适的体验&#xff0c;受到了健身爱好者们的广泛好评。这类耳机不同于我们常见的入耳式耳机&#xff0c;它的工作方式是直接通过振动将声音传递到用户的耳骨中&#xff0c;这样既可以享受音乐&a…

【nowcoder】链表的回文结构

牛客题目链接 链表的回文结构 /* struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {} };*/ #include <cstdlib> // 建议大伙自己对照我的代码画下图&#xff0c;假设A链表是&#xff1a;1 2 3 2 1 class PalindromeList { publi…

【学网攻】 第(7)节 -- 生成树配置

文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节 -- 交换机划分Vlan【学网攻】 第(5)节 -- Cisco VTP的使用【学网攻】 第(6)节 -- 三层交换机实现VLAN间路由 前言 网络已经成为…

vscode 如何指定启动文件?

launch.json 里面可以指定&#xff0c;launch.json 在打开文件夹的时候可以创建&#xff0c;或者手动创建

不合格机器人工程讲师再读《悉达多》-2024-

一次又一次失败的经历&#xff0c;让我对经典书籍的认同感越来越多&#xff0c;越来越觉得原来的自己是多么多么的无知和愚昧。 ----zhangrelay 唯物也好&#xff0c;唯心也罢&#xff0c;我们都要先热爱这个世界&#xff0c;然后才能在其中找到自己所热爱的事业。 ----zh…

vue2项目打包到测试环境之后报错require is not defined

配置打包命令npm run build:test到测试环境之后报错&#xff0c;打包到生产环境没有问题&#xff0c;查找了项目中的require引入似乎也没啥有问题的地方&#xff0c;所以排除是require的原因 环境变量文件&#xff1a; 打包指令&#xff1a; 解决办法&#xff1a; 将.env.tes…

[docker] Docker 网络和Cgroup

一、Docker 网络 1.1 Docker 网络实现原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c;同时Docker网桥是每个容器的默认…

【C/C++】C/C++编程——C++ 开发环境搭建

C的开发环境种类繁多&#xff0c;以下是一些常见的C 集成开发环境&#xff1a; AppCode &#xff1a;构建与JetBrains’ IntelliJ IDEA 平台上的用于Objective-C&#xff0c;C,C&#xff0c;Java和Java开发的集成开发环境CLion&#xff1a;来自JetBrains的跨平台的C/C的集成开…

《动手学深度学习(PyTorch版)》笔记2

Chapter2 Preliminaries 2.1 Automatic Differentiation 让计算机实现微分功能&#xff0c; 有以下四种方式&#xff1a; - 手工计算出微分&#xff0c; 然后编码进代码 - 数值微分 (numerical differentiation) - 符号微分 (symbolic differentiation) - 自动微分&#xff0…

java web mvc-03-JFinal

拓展阅读 Spring Web MVC-00-重学 mvc mvc-01-Model-View-Controller 概览 web mvc-03-JFinal web mvc-04-Apache Wicket web mvc-05-JSF JavaServer Faces web mvc-06-play framework intro web mvc-07-Vaadin web mvc-08-Grails JFinal JFinal 是基于 Java 语言的极…

Shell脚本③条件语句、if命令和case命令

目录 一.条件语句 1.test测试条件表达式 2.整数数值比较 &#xff08;1&#xff09;比较两个整数大小 &#xff08;2&#xff09;查看系统剩余内存是否低于1024M 3.逻辑测试 4.三元运算符 二.if命令 1.单分支结构 2.双分支结构 3.多分支结构 三.case语句 四.脚本 …