Create, trigger and listen for custom events in vanilla JavaScript and React.
📦 Small package (~19 kB)
🍃 Tree-shakeable
📝 Well documented
🛡️ Strictly typed with TypeScript
♻️ Events interact with each other across different browser tabs
⚛️ Exports a convenient hook for React developers
import { notifyEventListeners, listenForEvents } from 'use-app-events';
// 1. Listen for an event
listenForEvents('media-resume', () => {
// do something when the event is emitted
});
// 2. Emit an event
notifyEventListeners('media-resume');
// 3. Listen for an event (it will only be processed once here)
listenForEvents.once('load-resource', async (url) => {
await fetch(url);
});
// 4. Emit an event with some data
notifyEventListeners(
'load-resource',
'https://www.npmjs.com/package/use-app-events'
);
// 5. Listen for multiple events
const unlisten = listenForEvents(['event-1', 'event-2'], (eventType, url) => {
if (eventType === 'event-1') {
// do something when 'event-1' is emitted
}
if (eventType === 'event-2') {
// do something when 'event-2' is emitted
}
});
// 6. Stop listening for events
unlisten();
// 7. Emit multiple events with some data
notifyEventListeners(
['event-1', 'event-2'],
'https://www.npmjs.com/package/use-app-events'
);
npm
npm install use-app-events
pnpm
pnpm add use-app-events
- notifyEventListeners
- Function to notify all listeners of the specified event type(s) subscribed via
listenForEvents
.
- Function to notify all listeners of the specified event type(s) subscribed via
- listenForEvents
- Function to subscribe and listen for the specified event type(s) to occur in the app.
- listenForEvents.once
- Function to subscribe and listen for the specified event type(s) to occur in the app once.
- useAppEvents
- Hook for managing application events in React.
- heap
- (readonly) Collection of resources operated by the package.
- options
- Collection of options used to adjust the behavior of the package.
-
Listen for events in React
import { useAppEvents } from 'use-app-events';
a. Listen for an event
const Component = () => { const { listenForEvents } = useAppEvents(); listenForEvents('event-A', (payload) => { // 1. Do something when 'event-A' is triggered... // 2. Process a payload if you expect it to be sent by `notifyEventListeners` }); };
b. Listen for multiple events
const Component = () => { const { listenForEvents } = useAppEvents(); listenForEvents(['event-A', 'event-B'], (eventType, payload) => { // 1. Do something when either 'event-A' or 'event-B' is triggered... // 2. Process a specific event by its type in `eventType` if (eventType === 'event-A') { console.log('We got an event A with some data', payload); } }); };
-
Notify the event listeners in React
a. Trigger an event
const Component = () => { const { notifyEventListeners } = useAppEvents(); // Notify the listeners of this event type with no data notifyEventListeners('event-A'); };
b. Trigger an event with some data
const Component = () => { const { notifyEventListeners } = useAppEvents(); const payload = { a: 1, b: 2 }; // Notify the listeners of this event type and give them some data notifyEventListeners('event-A', payload); };
c. Trigger multiple events with some data at once
const Component = () => { const { notifyEventListeners } = useAppEvents(); const payload = { a: 1, b: 2 }; // Notify the listeners of these event types and give them some data notifyEventListeners(['event-A', 'event-B'], payload); };
d. Trigger multiple events with some data, but don't broadcast
const Component = () => { const { notifyEventListeners } = useAppEvents(); const payload = { a: 1, b: 2 }; // Notify the listeners of this event type in the current tab only notifyEventListeners('event-A', payload, false); // Notify the listeners of these event types in the current tab only notifyEventListeners(['event-B', 'event-C'], payload, false); };
-
Adjust options
import options from 'use-app-events/options'; import notifyEventListeners from 'use-app-events/notifyEventListeners';
a. Disable event broadcasting globally
options.broadcast = false; // From now on, notifyEventListeners will send events to the listeners of the current tab only by default notifyEventListeners('event-A', 'some-payload');
b. Enable the debug mode globally
options.debug = true; // From now on, listenForEvents and notifyEventListeners will output additional console logs on different stages listenForEvents('event-A', () => {}); notifyEventListeners('event-A', 'some-payload');
-
It is recommended to have a list of event types that can be used in your app, for example, enum called
EventType
, and pass it touseAppEvents()
for type safety and misprint-proof:
This way you are protected from the unexpected event types...
...and only allowed to use the expected ones.
-
However, if
EventType
is not provided, anystring
orenum
can be used:
Hook for managing application events in React.
useAppEvents<EventType extends string>(args): result
- args?: {
/** When true, enables a debug mode in non-production environment. */
debug: boolean;
}
- result: {
/** [Overload 1] Subscribe and listen for the specified event type to occur in the app. */
function listenForEvents<Payload>(
eventType: EventType,
callback:
| Callback<void>
| Callback<Payload>
| AsyncCallback<void>
| AsyncCallback<Payload>
): CleanupFunction;
/** [Overload 2] Subscribe and listen for the specified event types to occur in the app. */
function listenForEvents<Payload>(
eventTypes: EventType[],
callback:
| Callback<void>
| Callback<Type>
| Callback<[Type, Payload]>
| AsyncCallback<void>
| AsyncCallback<Type>
| AsyncCallback<[Type, Payload]>
): CleanupFunction;
/** [Overload 1] Notify all listeners of the specified event type subscribed via `listenForEvents`. */
function notifyEventListeners<Payload>(
/** Listeners of this event type will be notified. */
eventType: EventType,
/** Data to send to listeners of this event type. */
payload?: Payload,
/** When false, the event is not sent to other browsing contexts (tabs, windows). */
broadcast?: boolean = options.broadcast
): void;
/** [Overload 2] Notify all listeners of the specified event types subscribed via `listenForEvents`. */
function notifyEventListeners<Payload>(
/** Listeners of these event types will be notified. */
eventTypes: EventType[],
/** Data to send to listeners of these event types. */
payload?: Payload,
/** When false, the event is not sent to other browsing contexts (tabs, windows). */
broadcast?: boolean = options.broadcast
): void;
}
The
notifyEventListeners
andlistenForEvents
functions are also available independently outside of theuseAppEvents
hook to be used beyond the React components/hooks.However, prefer
useAppEvents
in React when possible.
Collection of resources operated by the package.
heap: {
/** The array of listeners used by the active `listenForEvents` instances. */
eventListeners: Listener[];
}
Collection of options used to adjust the behavior of the package.
options: {
/** When false, `notifyEventListeners` will not broadcast events to other browsing contexts (tabs, windows) by default. */
broadcast: boolean = true;
/** When true, the debug mode will be enabled globally, resulting in additional logs. */
debug: boolean = false;
}
The motivation to create use-app-events
was to find a way to manage the state from any part of the app (globally) and allow all elements to communicate with each other regardless of their position in the tree.
Clone the repository, install dependencies, and run the dev
script to start a web app and play around with examples.
pnpm
git clone https://github.com/aimtbr/use-app-events.git && cd use-app-events && pnpm install && pnpm dev
npm
git clone https://github.com/aimtbr/use-app-events.git && cd use-app-events && npm install && npm run dev
Maksym Marchuk