Skip to content

Instantly share code, notes, and snippets.

@yuhr
Created April 27, 2023 06:05
Show Gist options
  • Save yuhr/372b78652b00fe891b56edcbe28b26d2 to your computer and use it in GitHub Desktop.
Save yuhr/372b78652b00fe891b56edcbe28b26d2 to your computer and use it in GitHub Desktop.
Preact Signals, but in React. Licensed under CC0-1.0.
import { useCallback, useSyncExternalStore } from "react"
class Signal<T> {
#value: T
constructor(value: T) {
this.#value = value
}
get value() {
return this.#value
}
set value(value: T) {
this.#value = value
for (const listener of this.#listeners) {
listener()
}
}
#listeners: Set<() => void> = new Set()
addListener(listener: () => void) {
this.#listeners.add(listener)
}
removeListener(listener: () => void) {
this.#listeners.delete(listener)
}
}
const useSignal = <T>(signal: Signal<T>): T => {
const subscribe = useCallback<(onStoreChange: () => void) => () => void>(
(onStoreChange) => {
signal.addListener(onStoreChange)
return () => {
signal.removeListener(onStoreChange)
}
},
[signal]
)
const getSnapshot = useCallback<() => T>(() => signal.value, [signal])
return useSyncExternalStore(subscribe, getSnapshot)
}
export { useSignal, Signal }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment