Skip to content

Instantly share code, notes, and snippets.

@rpggio
Created October 27, 2020 02:56
Show Gist options
  • Save rpggio/9eefae2bf730dba7288eb201f8583495 to your computer and use it in GitHub Desktop.
Save rpggio/9eefae2bf730dba7288eb201f8583495 to your computer and use it in GitHub Desktop.
Reactive Map that can be subscribed, such as by React hooks
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