一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
响应式系统原理
本章的目的是通过模拟 Vue3 的响应式原理,来学习Vue3 的响应式原理
Vue.js 响应式回顾
首先我们需要先回顾一下 Vue3 的响应式
- Proxy 对象实现属性监听
- 多层属性嵌套,在访问属性过程中处理下一级属性
- 默认监听动态添加的属性
- 默认监听属性的删除操作
- 默认监听数组索引和 length 属性
- 可以作为独立的模块使用 好的目标明确,接下来我们要实现的就是如下的几个核心方法
- reactive/ref/torefs/computed
- effect
- track
- trigger
reactive
- 接收一个参数,判断这参数是否是对象
- 创建拦截器对象 handler, 设置 get/set/deleteProperty
- 返回 Proxy 对象 好,这里我们就按照上面总结的几个小点来进行模块的实现
1.接收一个参数,判断这参数是否是对象
// 判断对象是否是对象
const isObject = val => val !== null && typeof val === 'object'
export function reactive(target) {
// 如果不是对象的话就直接返回
if(!isObject(target)) return target
}
2.创建拦截器对象 handler, 设置 get/set/deleteProperty
const handler = {
get(target, key, receiver) {
// 收集依赖
},
set(target, key, value, receiver) {
},
deleteProperty(target, key) {
}
}
- get 函数设置
get(target, key, receiver) {
const result = Reflect.get(target, key, reactive)
},
这里有一个小问题,如果返回的 result 还是一个对象怎么办呢?
优化
const convent = target => isObject(target) ? reactive(target) : target
get(target, key, receiver) {
// 收集依赖
console.log('get', key)
const result = Reflect.get(target, key, reactive)
return convent(result)
},
- set 函数设置
// set 方法需要返回一个布尔类型的值,表示赋值是否成功
set(target, key, value, receiver) {
// 获取旧值的目的是为了和新值比对是否相等,如果相等就不需要任何处理
// 如果不相等 就要调用Reflect.set 方法去重新处理这个值
// 并且需要重新触发更新
const oldValue = Reflect.get(target, key, receiver)
let result = true
if(oldValue !== value) {
result = Reflect.set(target, key, value, receiver)
// 触发更新
console.log('set', key, value)
}
return result
},
- deleteProperty 函数设置 我们需要先判断 target 中是否有自己的 key属性, 如果有 key 属性, 删除成功之后,需要通知更新
deleteProperty(target, key) {
const hadKey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if(hadKey && result){
// 触发更新
console.log('delete', ley)
}
return result
}
测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="module">
import { reactive } from './reactivity/index.js'
const obj = reactive({
name: 'zs',
age: 18
})
obj.name = 'lisi'
delete obj.age
console.log(obj)
</script>
</body>
</html>
到这里 我们的 reactive 函数就演示完毕了,下一章就需要进行依赖收集等环节了!