Created
October 27, 2020 02:56
-
-
Save rpggio/9eefae2bf730dba7288eb201f8583495 to your computer and use it in GitHub Desktop.
Reactive Map that can be subscribed, such as by React hooks
This file contains 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
export function ReactiveMap<K, V>(map: Map<K, V>): ReactiveMap<K, V> { | |
const subscribers = new Set<Subscriber<MapState<K, V>>>() | |
function notify() { | |
const state: MapState<K, V> = [Array.from(map.entries()), map] | |
subscribers.forEach(subscriber => subscriber(state)) | |
} | |
function unsubscribe(subscriber: Subscriber<MapState<K, V>>) { | |
subscribers.delete(subscriber) | |
} | |
const newMap: ReactiveMap<K, V> = { | |
clear() { | |
map.clear() | |
notify() | |
}, | |
delete(key: K) { | |
const result = map.delete(key) | |
notify() | |
return result | |
}, | |
forEach: map.forEach, | |
get: map.get, | |
has: map.has, | |
set(key: K, value: V) { | |
const result = map.set(key, value) | |
notify() | |
return newMap | |
}, | |
size: map.size, | |
[Symbol.iterator]: () => map.entries(), | |
entries: () => map.entries(), | |
keys: () => map.keys(), | |
values: () => map.values(), | |
[Symbol.toStringTag]: map[Symbol.toStringTag], | |
subscribe(subscriber: Subscriber<MapState<K, V>>) { | |
subscribers.add(subscriber) | |
return () => unsubscribe(subscriber) | |
}, | |
unsubscribe | |
} | |
return newMap | |
} | |
export type MapState<K, V> = [[key: K, value: V][], Map<K, V>] | |
export type ReactiveMap<K, V> = Map<K, V> & Reactive<MapState<K, V>> | |
export type Reactive<T> = { | |
subscribe(subscriber: Subscriber<T>): VoidFunction | |
unsubscribe(subscriber: VoidFunction): void | |
} | |
export type Subscriber<S> = (s: S) => void |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment