Skip to content

Instantly share code, notes, and snippets.

@danybeltran
Last active December 13, 2024 19:32
Show Gist options
  • Save danybeltran/1f207725a9e2dcb3bfa2edff9abbee9c to your computer and use it in GitHub Desktop.
Save danybeltran/1f207725a9e2dcb3bfa2edff9abbee9c to your computer and use it in GitHub Desktop.
Boilerplate for a state management library with React.useSyncExternalStore
import { useSyncExternalStore } from "react"
const cache = new Map()
function defaultActions() {
return {}
}
type StateType<R, actionsType> = {
key: string
default: R
actions?: ({
dispatch,
}: {
dispatch: React.Dispatch<React.SetStateAction<R>>
}) => actionsType
}
/**
* Creates a stateful store
*/
export function create<T = any, actionsType = {}>(
config: StateType<T, actionsType>
) {
const { key, default: initialValue, actions } = config
if (!cache.has(key)) cache.set(key, initialValue)
const listeners = new Set<any>()
function setValue(value: React.SetStateAction<T>) {
const currentValue = cache.get(key)
const newValue =
typeof value === "function" ? (value as any)(currentValue) : value
cache.set(key, newValue)
listeners.forEach((listener) => {
listener(newValue)
})
}
const cachedActions = ((actions ||
defaultActions) as unknown as typeof actions)!({
dispatch: setValue,
})
return {
/**
* Use the current state of the store
*/
use() {
function subscribe(listener: (updatedValue: T) => void) {
listeners.add(listener)
return () => listeners.delete(listener)
}
function getSnapshot() {
return cache.get(key)
}
return useSyncExternalStore<T>(subscribe, getSnapshot, getSnapshot)
},
/**
* Set the store value
*/
setValue,
/**
* Store actions
*/
actions: cachedActions,
} as const
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment