Skip to content

Instantly share code, notes, and snippets.

@themarcba
Last active May 8, 2024 03:31
Show Gist options
  • Save themarcba/42368b29beddbc5c4755e40bf85ba825 to your computer and use it in GitHub Desktop.
Save themarcba/42368b29beddbc5c4755e40bf85ba825 to your computer and use it in GitHub Desktop.
Vue.js Global - Vue 3 Reactivity Under The Hood
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
// ----------------------------------------------------------------
// 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
}
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