思路
- 保存未来执行修改的代码(effect)。
- 监测值的改变
- 使用
proxy 对
象实现
- 使用
- 值改变后,执行 trigger effect
监测值的改变
```typescript const person = { name: ‘Jone’ } const handler = { // 目标对象,属性名,代理对象 get(target, prop, receiver) { console.log(‘trigger get’, target, prop) return target[prop] }, // 目标对象,属性名,要填入的值,代理对象 set(target, prop, value, receiver) { console.log(‘trigger set’, target, prop, value) target[prop] = value return true // 告诉设置成功 } } const proxy = new Proxy(person, handler)
proxy.name = ‘111’
使用` Reflect `对象上的静态方法改写:
```typescript
console.log(Reflect.get(person, 'name'))
console.log(Reflect.set(person, 'name','maomao'))
console.log(Reflect.get(person, 'name'))
const person = {
name: 'Jone'
}
const handler = {
get() {
console.log('trigger get')
return Reflect.get(...arguments) // Reflect.get() 接收的参数和 handler.get 接收的参数一样
},
set() {
console.log('trigger set')
return Reflect.set(...arguments) // Reflect.set() 接收的参数和 handler.set 接收的参数一样
}
}
const proxy = new Proxy(person, handler)
proxy.name = '111'
存储和触发 effect
- 将所有
effect
加入特定的数据结构 - 创建特定的函数可以再次运行这些
effect
- 使用
Proxy
的getter
和setter
,将这些函数放入对应的位置
原生示例:
let product = { price: 5, count: 2 }
let total = 0
let effect = () => {
total = product.price * product.count
}
effect()
console.log(total);
product.price = 10
effect()
console.log(`total is ${total}`);
let product = { price: 5, count: 2 }
let total = 0
let dep = new Set()
// 将所有 effect 加入特定的数据结构
function track() {
dep.add(effect)
}
// 创建特定的函数可以再次运行这些 effect
function trigger() {
dep.forEach(effect => effect());
}
let effect = () => {
total = product.price * product.count
}
effect()
console.log(total);
track()
product.price = 10
trigger()
console.log(`total is ${total}`);
Proxy响应式封装
- get的时候触发收集effect
- set的时候触发effect执行 ```typescript
let total = 0
let dep = new Set()
// 存储effect
function track() {
dep.add(effect)
}
// 遍历执行effect
function trigger() {
dep.forEach(effect => effect());
}
// 响应式封装
const reactive = (obj) => {
const handler = {
get() {
let result = Reflect.get(…arguments)
track()
return result
},
set() {
let result = Reflect.set(…arguments)
trigger()
return result
}
}
return new Proxy(obj, handler)
}
let effect = () => {
total = product.price * product.count
}
const product = reactive({ price: 5, count: 2 })
effect()
console.log(total);
product.price = 10
console.log(total is ${total}
);
```