响应式机制的主要功能就是,可以把普通的 JavaScript 对象封装成为响应式对象,拦截数据的获取和修改操作,实现依赖数据的自动化更新。
一个最简单的响应式模型,我们可以通过 reactive 或者 ref 函数,把数据包裹成响应式对象,并且通过 effect 函数注册回调函数,然后在数据修改之后,响应式地通知 effect 去执行回调函数即可。
Vue 的响应式是可以独立在其他平台使用的。比如你可以新建 test.js,使用下面的代码在 node 环境中使用 Vue 响应。以 reactive 为例,我们使用 reactive 包裹 JavaScript 对象之后,每一次对响应式对象 counter 的修改,都会执行 effect 内部注册的函数:
const {
effect, reactive} = require('@vue/reactivity')
let dummy
const counter = reactive({
num1: 1, num2: 2 })
effect(() => {
dummy = counter.num1 + counter.num2
console.log(dummy)// 每次counter.num1修改都会打印日志
})
setInterval(()=>{
counter.num1++
},1000)
import {
effect } from '../effect'
import {
reactive } from '../reactive'
describe('测试响应式', () => {
test('reactive基本使用', () => {
const ret = reactive({
num: 0 })
let val
effect(() => {
val = ret.num
})
expect(val).toBe(0)
ret.num++
expect(val).toBe(1)
ret.num = 10
expect(val).toBe(10)
})
})
export function reactive(target) {
if (typeof target!=='object') {
console.warn(`reactive ${
target} 必须是一个对象`);
return target
}
return new Proxy(target, mutableHandlers);
}
const get = createGetter();
const set = createSetter();
function createGetter(shallow = false) {
return function get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
track(target, "get", key)
if (isObject(res)) {
// 值也是对象的话,需要嵌套调用reactive
// res就是target[key]
// 浅层代理,不需要嵌套
return shallow ? res : reactive(res)
}
return res
}
}
function createSetter() {
return function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
// 在触发 set 的时候进行触发依赖
trigger(target, "set", key)
return result
}
}
export const mutableHandles = {
get,
set,
};
const targetMap = new WeakMap()
export function track(target, type, key) {
// console.log(`触发 track -> target: ${target} type:${type} key:${key}`)
// 1. 先基于 target 找到对应的 dep
// 如果是第一次的话,那么就需要初始化
// {
// target1: {//depsmap
// key:[effect1,effect2]
// }
// }
let depsMap = targetMap.get(target)
if (!depsMap) {
// 初始化 depsMap 的逻辑
// depsMap = new Map()
// targetMap.set(target, depsMap)
// 上面两行可以简写成下面的
targetMap.set(target, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
}
if (!deps.has(activeEffect) && activeEffect) {
// 防止重复注册
deps.add(activeEffect)
}
depsMap.set(key, deps)
}
响应式的主要功能就是可以把普通的 JavaScript 对象封装成为响应式对象,在读取数据的时候通过 track 收集函数的依赖关系,把整个对象和 effect 注册函数的依赖关系全部存储在一个依赖图中。
在日常项目开发中也可以借鉴响应式的处理思路,使用通知的机制,来调用具体数据的操作和更新逻辑,灵活使用 effect、ref、reactive 等函数把常见的操作全部变成响应式数据处理,会极大的提高我们开发的体验和效率。
夜深了,没写完,有疑问私信我吧…