Skip to content

Instantly share code, notes, and snippets.

@ycmjason
Created February 26, 2020 16:26
Show Gist options
  • Save ycmjason/ebc2faeb500186cc4440a890396be81b to your computer and use it in GitHub Desktop.
Save ycmjason/ebc2faeb500186cc4440a890396be81b to your computer and use it in GitHub Desktop.
import debounce from 'lodash.debounce'
const dependencies = new Set<symbol>() // 1. keep track of dependencies
const watchers: ({
callback: () => any,
dependencies: Set<symbol>,
})[] = []
const watch = (callback: () => any) => {
dependencies.clear() // 2. clear dependencies
callback()
// 4. dependencies is populated
watchers.push({
callback: debounce(callback, 0),
dependencies: new Set(dependencies), // make a copy
})
}
const reactive = <T extends object>(t: T): T => {
const keyToSymbolMap = new Map<keyof T, symbol>()
const getSymbolForKey = (key: keyof T): symbol => {
const symbol = keyToSymbolMap.get(key) || Symbol()
if (!keyToSymbolMap.has(key)) {
keyToSymbolMap.set(key, symbol)
}
return symbol
}
return new Proxy(t, {
set(target, key: keyof T, value) {
target[key] = value
// 5. only trigger watchers depending on this property
watchers
.filter(({ dependencies }) => dependencies.has(getSymbolForKey(key)))
.forEach(({ callback }) => callback())
return true
},
get(target, key: keyof T) {
dependencies.add(getSymbolForKey(key)) // 3. add symbol to dependencies
return target[key]
},
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment