Last active
February 23, 2021 10:32
-
-
Save secf4ult/fe94b410534af37c560915e292bc68fe to your computer and use it in GitHub Desktop.
Simple Vue reactivity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const targetMap = new WeakMap() | |
let activeEffect = null | |
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(activeEffect) | |
} | |
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 | |
if (activeEffect) { | |
track(target, key) | |
} | |
return result | |
}, | |
set(target, key, value, receiver) { | |
let oldValue = target[key] | |
let result = Reflect.set(target, key, value, receiver) | |
if (oldValue !== result) { | |
// trigger | |
trigger(target, key) | |
} | |
return result | |
}, | |
} | |
return new Proxy(target, handler) | |
} | |
function effect(eff) { | |
activeEffect = eff | |
activeEffect() | |
activeEffect = null | |
} | |
function ref(raw) { | |
const r = { | |
get value() { | |
if (activeEffect) track(r, 'value') | |
return raw | |
}, | |
set value(newVal) { | |
if (raw !== newVal) { | |
raw = newVal | |
trigger(r, 'value') | |
} | |
}, | |
} | |
return r | |
} | |
let product = reactive({ price: 5, quantity: 2 }) | |
let salePrice = ref(0) | |
let total = 0 | |
effect(() => { | |
total = salePrice.value * product.quantity | |
}) | |
effect(() => { | |
salePrice.value = product.price * 0.9 | |
}) | |
console.log( | |
`Before updated total (should be 10) = ${total} salePrice (should be 4.5) = ${salePrice}` | |
) | |
product.quantity = 3 | |
console.log( | |
`After updated total (should be 15) = ${total} salePrice (should be 4.5) = ${salePrice}` | |
) | |
product.price = 10 | |
console.log( | |
`After updated total (should be 30) = ${total} salePrice (should be 9) = ${salePrice}` | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment