Last active
May 8, 2024 03:31
-
-
Save themarcba/42368b29beddbc5c4755e40bf85ba825 to your computer and use it in GitHub Desktop.
Vue.js Global - Vue 3 Reactivity Under The Hood
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
This is an addition to my Vue.js Global 2020 talk about Vue 3 Reactivity. | |
Some people asked for the slides. You can find them here: | |
https://marcbackes.com/d8qaLT |
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
// ---------------------------------------------------------------- | |
// Vue.js Global - Vue 3 Reactivity | |
// Marc Backes | |
// ---------------------------------------------------------------- | |
let activeEffect = null | |
let targetMap = new WeakMap() | |
// Register an effect | |
function track(target, key) { | |
if (activeEffect) { | |
// Get depsMap from targetMap | |
let depsMap = targetMap.get(target) | |
if (!depsMap) { | |
depsMap = new Map() | |
targetMap.set(target, depsMap) | |
} | |
// Get dep from depsMap | |
let dep = depsMap.get(key) | |
if (!dep) { | |
dep = new Set() | |
depsMap.set(key, dep) | |
} | |
// Add effect | |
dep.add(activeEffect) | |
} | |
} | |
// Execute all registered effects for the target/key combination | |
function trigger(target, key) { | |
// Get depsMap from targetMap | |
let depsMap = targetMap.get(target) | |
if (!depsMap) { | |
// If there is no depsMap, no need to resume | |
return | |
} | |
// Get dep from depsMap | |
let dep = depsMap.get(key) | |
if (!dep) { | |
// If there is no dep, no need to resume | |
return | |
} | |
// Execute all effects | |
dep.forEach((effect) => effect()) | |
} | |
// Make an object reactive | |
function reactive(target) { | |
const handler = { | |
// Intercept getter | |
get(target, key, receiver) { | |
const result = Reflect.get(target, key, receiver) | |
track(target, key) | |
return result | |
}, | |
// Intercept setter | |
set(target, key, value, receiver) { | |
const result = Reflect.set(target, key, value, receiver) | |
trigger(target, key) | |
return result | |
}, | |
} | |
return new Proxy(target, handler) | |
} | |
// Watcher | |
function effect(fn) { | |
activeEffect = fn | |
// Only execute when there is an activeEffect | |
if (activeEffect) activeEffect() | |
activeEffect = null | |
} | |
// The ref class is a reactive object with a single value (called "value") | |
function ref(raw) { | |
let r = { | |
// Intercept getter | |
get value() { | |
track(r, 'value') | |
return raw | |
}, | |
// Intercept setter | |
set value(newValue) { | |
raw = newValue | |
trigger(r, 'value') | |
} | |
} | |
return r | |
} |
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
let activeEffect = null | |
let dep = new Set() | |
function track() { | |
if (activeEffect) { | |
dep.add(activeEffect) | |
} | |
} | |
function trigger() { | |
dep.forEach((effect) => effect()) | |
} | |
function reactive(target) { | |
const handler = { | |
get(target, key, receiver) { | |
const result = Reflect.get(target, key, receiver) | |
track() | |
return result | |
}, | |
set(target, key, value, receiver) { | |
const result = Reflect.set(target, key, value, receiver) | |
trigger() | |
return result | |
}, | |
} | |
return new Proxy(target, handler) | |
} | |
function effect(fn) { | |
activeEffect = fn | |
if (activeEffect) activeEffect() | |
activeEffect = null | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment