Skip to content

Instantly share code, notes, and snippets.

@tonis2
Last active February 27, 2019 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonis2/4575501d991cb8d1f62868eff07d9e0f to your computer and use it in GitHub Desktop.
Save tonis2/4575501d991cb8d1f62868eff07d9e0f to your computer and use it in GitHub Desktop.
ES6 light version of Object observing + easy to listen state change
export default class Observer {
constructor(data) {
this.listeners = []
this.preproxy = new WeakMap()
this.state = this.proxify(data, [])
}
listen(callback) {
this.listeners.push(callback)
}
getHandler(path) {
const proxify = this.proxify
const unproxy = this.unproxy
const listeners = this.listeners
return {
set(target, key, value, receiver) {
if (typeof value === "object") {
value = proxify(value, [...path, key])
}
target[key] = value
const changes = { target, path: [...path, key], value, receiver }
listeners.forEach(callback => callback(changes))
return true
},
deleteProperty(target, key) {
if (Reflect.has(target, key)) {
unproxy(target, key)
let deleted = Reflect.deleteProperty(target, key)
if (deleted && handler.deleteProperty) {
const changes = { target, path: [...path, key] }
listeners.forEach(callback => callback(changes))
}
return deleted
}
return false
}
}
}
unproxy(obj, key) {
if (preproxy.has(obj[key])) {
obj[key] = preproxy.get(obj[key])
preproxy.delete(obj[key])
}
for (let k of Object.keys(obj[key])) {
if (typeof obj[key][k] === "object") {
unproxy(obj[key], k)
}
}
}
proxify(obj, path) {
for (let key of Object.keys(obj)) {
if (typeof obj[key] === "object") obj[key] = this.proxify(obj[key], [...path, key])
}
let p = new Proxy(obj, this.getHandler(path))
this.preproxy.set(p, obj)
return p
}
}
@tonis2
Copy link
Author

tonis2 commented Feb 27, 2019

Example

State

const state = {
  "online": true,
  "userData": {
    "loggedIn":false
  }
}

Init observer

const observe = new Observer(state)

Listen to changes

const change = (data) => console.log(data)

observe.listen(change)
observe.state.userData.loggedIn = true

Returns

{
 path: (2) ["userData", "loggedIn"]
 receiver: Proxy {loggedIn: true}
 target: {loggedIn: true}
 value: true
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment