Skip to content

Instantly share code, notes, and snippets.

@darthtrevino
Last active January 28, 2022 07:24
Show Gist options
  • Save darthtrevino/a0f00fbfd3cd95e4c6086356ee5172c5 to your computer and use it in GitHub Desktop.
Save darthtrevino/a0f00fbfd3cd95e4c6086356ee5172c5 to your computer and use it in GitHub Desktop.
type Unsubscribe = () => void
type EffectId = string | symbol
type EffectFn = () => Unsubscribe | undefined
class SideEffects implements ReactiveController {
private effectDeps: Record<EffectId, unknown[]> = {}
private effectUnsubscribes: Record<EffectId, Unsubscribe | undefined> = {}
public constructor(private host: ReactiveControllerHost & Element) {
this.host.addController(this);
}
public useEffect(id: EffectId, effect: EffectFn, deps: unknown[]) {
if (this.shouldEffectRun(deps, this.effectDeps[id])) {
// invoke old cleanups
const prevUnsubscribe = this.effectUnsubscribes[id]
if (prevUnsubscribe) {
prevUnsubscribe()
this.effectUnsubscribes[id] = undefined
}
// run the effect
const unsubscribe = effect()
if (unsubscribe) {
this.effectUnsubscribes[id] = unsubscribe
}
}
}
public hostConnected() {
this.clear()
}
public hostDisconnected() {
Object.values(this.effectUnsubscribes).forEach(u => u())
this.clear()
}
private clear() {
this.effectDeps = {}
this.effectUnsubscribes = {}
}
private shouldEffectRun(currDeps: unknown[], prevDeps: unknown[]): boolean {
if (!prevDeps) return true
if (currDeps.length !== prevDeps.length) throw new Error('effect dependency length should not change');
return currDeps.every((value, idx)=> prevDeps[idx] === value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment