Vue.js-like reactive state
<script> | |
let activeEffect | |
class Dep { | |
subscribers = new Set() | |
depend() { | |
if (activeEffect) this.subscribers.add(activeEffect) | |
} | |
notify() { | |
this.subscribers.forEach((sub) => sub()) | |
} | |
} | |
function watchEffect(fn) { | |
const wrappedFn = () => { | |
activeEffect = wrappedFn | |
// clean up the deps | |
fn() | |
activeEffect = null | |
} | |
wrappedFn() | |
} | |
function reactive(obj) { | |
Object.keys(obj).forEach((key) => { | |
const dep = new Dep() | |
let value = obj[key] | |
Object.defineProperty(obj, key, { | |
get() { | |
dep.depend() | |
return value | |
}, | |
set(newValue) { | |
if (newValue !== value) { | |
value = newValue | |
dep.notify() | |
} | |
}, | |
}) | |
}) | |
return obj | |
} | |
// ------------------------- | |
const state = reactive({ | |
count: 1, | |
name: 'Marc', | |
}) | |
watchEffect(() => { | |
console.log('👻 state changed', state.count, state.name) | |
}) | |
setTimeout(() => { | |
state.count++ | |
state.name = 'Johnny' | |
}, 1000) | |
setTimeout(() => { | |
state.count++ | |
}, 2000) | |
setTimeout(() => { | |
state.count++ | |
}, 3000) | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment