Skip to content

Instantly share code, notes, and snippets.

@rpggio
Last active November 5, 2020 22:14
Show Gist options
  • Save rpggio/aa4b0615e2f83df11767141f2cfb6009 to your computer and use it in GitHub Desktop.
Save rpggio/aa4b0615e2f83df11767141f2cfb6009 to your computer and use it in GitHub Desktop.
Basic reactive store
import type { Reactive, Subscriber, Store } from './types'
export function Store<S>(initial: S): Store<S> {
let current = initial
const subscribers = new Set<Subscriber<S>>()
function subscribe(subscriber: Subscriber<S>) {
subscribers.add(subscriber)
return () => unsubscribe(subscriber as VoidFunction)
}
function unsubscribe(subscriber: VoidFunction) {
subscribers.delete(subscriber)
}
function writeState(newState: S) {
current = newState
for (const subscriber of subscribers) {
subscriber(newState)
}
}
return {
subscribe,
unsubscribe,
getState() {
return current
},
setState(setter: S | ((s: S) => S)) {
if (typeof setter === 'function') {
writeState((setter as ((s: S) => S))(current))
} else {
writeState(setter as S)
}
}
}
}
export type Reactive<T> = {
subscribe(subscriber: Subscriber<T>): VoidFunction
unsubscribe(subscriber: VoidFunction): void
}
export type Subscriber<S> = (s: S) => void
export type Store<S> = Reactive<S> & {
getState(): S
setState(setter: S | ((s: S) => S)): void
}
import { useEffect, useState } from 'react'
import type { Reactive, Store } from './types'
export function useStore<S>(store: Store<S>) {
const { getState, setState, subscribe } = store
const initial = getState()
const [state, setLocalState] = useState<S>(initial)
useEffect(() => subscribe(setLocalState), [subscribe])
return tuple(
state,
setState,
store
)
}
function tuple<T extends any[]>(...elements: T) {
return elements
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment