Last active
July 24, 2019 19:31
-
-
Save KargJonas/a0aac5b1ad189676da58cb11a032cf9a to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // Selecting an element | |
| const counterElement = document.querySelector("#counter"); | |
| // Creating a mutable (the "new" is unnecessary, just looks cool) | |
| const state = new Mutable({ | |
| count: 0 | |
| }); | |
| // Subscribing to it (update the content of our element, when mutable changes) | |
| state.$subscribe(() => { | |
| counterElement.innerHTML = state.count; | |
| }); | |
| // Incrementing the counter => automatically updates element's innerHTML | |
| setInterval( | |
| () => state.count++, | |
| 1000 | |
| ); |
This file contains hidden or 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
| /** | |
| * Mutable: | |
| * A proxy with some more features. | |
| * - Multi-Subscriptions on the fly | |
| * - Optional Recursion (sub objects will also be proxies) | |
| * | |
| * Mutable(<initialObject>, <recursive>) // create a Mutable, parameters default to ({}, false) | |
| * <>.$subscribe(<subscriberFunc>) // subscribe to the Mutable - returns an id | |
| * <>.$unsubscribe(<id>) // unsubscribes a function by it's id | |
| * <>.$callSubscriptions() // call all subscriber-functions | |
| * | |
| * I built it this weird because Proxy has no prototype and | |
| * thus is not extensible. The setter checks, if the property | |
| * begins with a "$" and if so, "switches the scope" to the | |
| * one of the Proxy's handler. This allows us to access methods | |
| * and data inside the handler within those methods. | |
| * | |
| * Subscribers of Mutable are called whenever | |
| * it's setter is triggered, even if the new data | |
| * is the same as the old. | |
| */ | |
| function Mutable(initial = {}, recursive = false) { | |
| const handler = { | |
| $subscriptions: [], | |
| $recursive: recursive, | |
| $handler: undefined, | |
| // Add a subscriber-function | |
| $subscribe(callback) { | |
| const id = this.$subscriptions.length; | |
| this.$subscriptions.push({ | |
| callback, | |
| id | |
| }); | |
| return id; | |
| }, | |
| // Remove a subscriber by it's id | |
| $unsubscribe(id) { | |
| const index = this | |
| .$subscriptions | |
| .findIndex((subscription) => (subscription.index === id)); | |
| this.$subscriptions[index] = null; | |
| }, | |
| // Call all subscriptions | |
| $callSubscriptions() { | |
| this.$subscriptions.map((subscription) => { | |
| subscription.callback(); | |
| }); | |
| }, | |
| // Convert all sub-objects of an object to State-proxies | |
| $convertSubObjectsToState(object, recursive = false) { | |
| if (typeof object !== "object" || object === null) { | |
| return object; | |
| } | |
| const newObject = {}; | |
| Object.keys(object).map((key) => { | |
| newObject[key] = this.$convertSubObjectsToState(object[key], true); | |
| newObject[key].$isProxy = true; | |
| }); | |
| if (recursive === true) { | |
| return Mutable(newObject); | |
| } | |
| return newObject; | |
| }, | |
| // Handling get | |
| set(obj, prop, value) { | |
| obj[prop] = this.$convertSubObjectsToState(value, this.$recursive); | |
| this.$callSubscriptions(); | |
| return true; | |
| }, | |
| // Handling set | |
| get(obj, prop) { | |
| if (prop[0] === "$") { | |
| return this[prop]; | |
| } | |
| return obj[prop]; | |
| } | |
| }; | |
| return new Proxy( | |
| recursive ? handler.$convertSubObjectsToState(initial) : initial, | |
| handler | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment