Created
September 12, 2024 12:48
-
-
Save denisputnov/8e53d557a513ffb0ecb45e6713a18e5e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {useEffect} from 'react'; | |
type EventKey = string; | |
type EventHandler<T = any> = (payload: T) => void; | |
type EventMap = Record<EventKey, EventHandler>; | |
type Bus<E> = Record<keyof E, E[keyof E][]>; | |
interface EventBus<T extends EventMap> { | |
on<Key extends keyof T>(key: Key, handler: T[Key]): () => void; | |
off<Key extends keyof T>(key: Key, handler: T[Key]): void; | |
once<Key extends keyof T>(key: Key, handler: T[Key]): void; | |
emit<Key extends keyof T>(key: Key, ...payload: Parameters<T[Key]>): void; | |
useEvent<Key extends keyof T>(key: Key, handler: T[Key]): void; | |
} | |
interface EventBusConfig { | |
onError: (...params: any[]) => void; | |
} | |
export const createEventChannel = <E extends EventMap>(config?: EventBusConfig): EventBus<E> => { | |
const bus: Partial<Bus<E>> = {}; | |
const on: EventBus<E>['on'] = (key, handler) => { | |
if (bus[key] === undefined) { | |
bus[key] = []; | |
} | |
bus[key]?.push(handler); | |
return () => { | |
off(key, handler); | |
}; | |
}; | |
const off: EventBus<E>['off'] = (key, handler) => { | |
const index = bus[key]?.indexOf(handler) ?? -1; | |
bus[key]?.splice(index >>> 0, 1); | |
}; | |
const once: EventBus<E>['once'] = (key, handler) => { | |
const handleOnce = (payload: Parameters<typeof handler>) => { | |
handler(payload); | |
off(key, handleOnce as typeof handler); | |
}; | |
on(key, handleOnce as typeof handler); | |
}; | |
const emit: EventBus<E>['emit'] = (key, payload) => { | |
bus[key]?.forEach(fn => { | |
try { | |
fn(payload); | |
} catch (e) { | |
config?.onError(e); | |
} | |
}); | |
}; | |
const useEvent: EventBus<E>['useEvent'] = (key, handler) => { | |
useEffect(() => { | |
return on(key, handler); | |
}, []); | |
}; | |
return {on, off, once, emit, useEvent}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment