const price = 5 let quantity = 2 let total = 0 let storage = 0
// Set对象是值的集合 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。 let dep = new Set()
let effect1 = () => { total = price * quantity } let effect2 = () => { storage = 100 - quantity }
function track() { dep.add(effect1) dep.add(effect2) } function trigger() { dep.forEach(effect => effect()) }
track() effect1() effect2()
// 运行 > total 10 > storage 98 > quantity = 5 5 > total 10 > storage 98 > trigger() undefined > total 25 > storage 95
步骤二: 追踪对象中的属性
let product = { price: 5, quantity: 2 } let total = 0
// Map 对象保存键值对。任何值都可以作为一个键或一个值 const depsMap = new Map()
let effect = () => { total = product.price * product.quantity }
function track(key) { let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = new Set())) } dep.add(effect) } function trigger(key) { let dep = depsMap.get(key) if (dep) { dep.forEach(effect => effect()) } }
track('price') track('quantity') effect()
// 运行 > total 10 > product.quantity = 8 8 > total 10 > trigger('price') undefined > total 16 > product.quantity = 4 4 > total 16 > trigger('quantity') undefined > total 32
let product = { price: 5, quantity: 2 } let total = 0 let storage = { amount: 50, sale: 2 } let remain = 48
let effect = () => { total = product.price * product.quantity remain = storage.amount - storage.sale }
function track(target, key) { 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())) } dep.add(effect) } function trigger(target, key) { let depsMap = targetMap.get(target) if (!depsMap) return let dep = depsMap.get(key) if (dep) { dep.forEach(effect => effect()) } }
// 运行 > proxiedProduct.price = 8 set < 8 > proxiedProduct.price get < 8
步骤二: 进一步封装
const targetMap = new WeakMap()
function track(target, key) { 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())) } dep.add(effect) } function trigger(target, key) { let depsMap = targetMap.get(target) if (!depsMap) return let dep = depsMap.get(key) if (dep) { dep.forEach(effect => effect()) } }
function reactive(target) { const handler = { get(target, key, receiver) { let result = Reflect.get(target, key, receiver) track(target, key) return typeof result === 'object' ? reactive(result) : result }, set(target, key, value, receiver) { let oldValue = target[key] let result = Reflect.set(target, key, value, receiver) if (oldValue !== value) { trigger(target, key) } return result } } return new Proxy(target, handler) }
let product = reactive({ price: 5, quantity: {a: 2} }) let total = 0 let effect = () => { total = product.price * product.quantity.a }
effect()
// 运行 > total < 10 > product.price = 8 < 8 > total < 16
步骤三: 移除非effect下的track,封装ref
let activeEffect = null
function track(target, key) { // 新增判断activeEffect,不是每次get都要track if (activeEffect) { 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())) } dep.add(activeEffect) } } // effect函数 function effect(eff) { activeEffect = eff activeEffect() activeEffect = null }
function ref(raw) { const r = { get value() { track(r, 'value') return raw }, set value(newValue) { if (raw !== newValue) { raw = newValue trigger(r, 'value') } } } return r }
let product = reactive({ price: 5, quantity: 2 }) let salePrice = ref(0) let total = 0