Standard Toolkit
Packages@accelint/bus

React Hooks

React hooks for type-safe event bus integration including useBus, useEmit, useOn, and useOnce.

Usage

import { useBus, Payload } from '@accelint/bus';

type MyEvents =
  | Payload<'user:login', { userId: string }>
  | Payload<'user:logout'>;

function MyComponent() {
  const { useEmit, useOn } = useBus<MyEvents>();

  const emitLogin = useEmit('user:login');
  useOn('user:logout', (event) => {
    console.log('User logged out');
  });

  return (
    <button onClick={() => emitLogin({ userId: '123' })}>
      Login
    </button>
  );
}

Reference

function useBus<Events extends BasicPayload>(
  options?: EmitOptions | null
): {
  useEmit: <Type extends Events['type']>(
    type: Type,
    options?: EmitOptions | null
  ) => EmitFunction;
  useOn: <Type extends Events['type']>(
    type: Type,
    callback: (data: ExtractEvent<Events, Type>) => void
  ) => void;
  useOnce: <Type extends Events['type']>(
    type: Type,
    callback: (data: ExtractEvent<Events, Type>) => void
  ) => void;
}

Parameters:

ParameterTypeDescription
optionsEmitOptions | nullOptional global emit options applied to all events. Can include target to scope delivery.

Returns: An object containing three type-safe hooks: useEmit, useOn, and useOnce

Type Parameters:

  • Events - Union type of all event payloads handled by this bus. Should be a union of Payload<type, data> types.

Examples

Example: Simple event communication

import { useBus, Payload } from '@accelint/bus';

type AppEvents = Payload<'theme:changed', { theme: 'light' | 'dark' }>;

function ThemeToggle() {
  const { useEmit } = useBus<AppEvents>();
  const emitThemeChange = useEmit('theme:changed');

  return (
    <button onClick={() => emitThemeChange({ theme: 'dark' })}>
      Dark Mode
    </button>
  );
}

function ThemeListener() {
  const { useOn } = useBus<AppEvents>();

  useOn('theme:changed', (event) => {
    document.body.className = event.payload.theme;
  });

  return null;
}

Example: Events without payload

import { useBus, Payload } from '@accelint/bus';

type NavigationEvents = Payload<'nav:back'>;

function BackButton() {
  const { useEmit } = useBus<NavigationEvents>();
  const goBack = useEmit('nav:back');

  // No payload required for events without data
  return <button onClick={() => goBack()}>Back</button>;
}

Example: Targeting specific instances

import { useBus, Payload } from '@accelint/bus';

type NotificationEvents = Payload<'notify', { message: string }>;

function Notifier() {
  const { useEmit } = useBus<NotificationEvents>({
    target: 'others' // Don't emit to self
  });

  const notify = useEmit('notify');

  return (
    <button onClick={() => notify({ message: 'Hello other tabs!' })}>
      Notify Others
    </button>
  );
}

Example: Multiple event types

import { useBus, Payload } from '@accelint/bus';

type AppEvents =
  | Payload<'user:login', { userId: string; username: string }>
  | Payload<'user:logout'>
  | Payload<'data:updated', { id: string }>;

function AppEventHandler() {
  const { useOn } = useBus<AppEvents>();

  useOn('user:login', (event) => {
    console.log(`Welcome ${event.payload.username}`);
  });

  useOn('user:logout', () => {
    console.log('Goodbye');
  });

  useOn('data:updated', (event) => {
    console.log(`Data ${event.payload.id} updated`);
  });

  return null;
}

Good to know: All three hooks (useEmit, useOn, useOnce) returned by useBus share the same underlying Broadcast singleton instance, ensuring events are delivered across all components using the same event types.


useEmit

React hook to enable render-safe emitting of events with type-safe payloads.

Usage

import { useEmit, Payload } from '@accelint/bus';

type MyEvents = Payload<'user:login', { userId: string }>;

function LoginButton() {
  const emitLogin = useEmit<MyEvents, 'user:login'>('user:login');

  return (
    <button onClick={() => emitLogin({ userId: '123' })}>
      Login
    </button>
  );
}

Reference

function useEmit<
  Events extends BasicPayload,
  Type extends Events['type']
>(
  type: Type,
  options?: EmitOptions | null
): EmitFunction

Parameters:

ParameterTypeDescription
typeType extends Events['type']Event type, one of the event types in the union
optionsEmitOptions | nullOptional emit options applied to all emits of this event

Returns: Callback that accepts the payload corresponding to the event type. The callback also accepts options parameter for per-call configuration.

Type Parameters:

  • Events - Union of event types
  • Type - Type of event

Examples

Example: Emitting with payload

import { useEmit, Payload } from '@accelint/bus';

type MyEvents = Payload<'map:click', { x: number; y: number }>;

function MapComponent() {
  const emitMapClick = useEmit<MyEvents, 'map:click'>('map:click');

  const handleClick = (x: number, y: number) => {
    emitMapClick({ x, y });
  };

  return <div onClick={(e) => handleClick(e.clientX, e.clientY)} />;
}

Example: Event-specific options

import { useEmit, Payload } from '@accelint/bus';

type MyEvents = Payload<'notification', { message: string }>;

function NotificationSender() {
  const emitNotification = useEmit<MyEvents, 'notification'>(
    'notification',
    { target: 'others' } // Always send to other instances
  );

  return (
    <button onClick={() => emitNotification({ message: 'Hi!' })}>
      Notify Others
    </button>
  );
}

useOn

React hook to attach event bus listener with type-safe callback.

Usage

import { useOn, Payload } from '@accelint/bus';

type MyEvents = Payload<'user:login', { userId: string }>;

function UserWatcher() {
  useOn<MyEvents, 'user:login'>('user:login', (event) => {
    console.log('User logged in:', event.payload.userId);
  });

  return null;
}

Reference

function useOn<
  Events extends BasicPayload,
  Type extends Events['type']
>(
  type: Type,
  callback: (data: ExtractEvent<Events, Type>) => void
): void

Parameters:

ParameterTypeDescription
typeType extends Events['type']Event type
callback(data: ExtractEvent<Events, Type>) => voidHandler that matches event type and receives corresponding payload

Type Parameters:

  • Events - Union of event types
  • Type - Type of event

Examples

Example: Listening to events

import { useOn, Payload } from '@accelint/bus';

type MyEvents = Payload<'cart:updated', { itemCount: number }>;

function CartBadge() {
  const [count, setCount] = React.useState(0);

  useOn<MyEvents, 'cart:updated'>('cart:updated', (event) => {
    setCount(event.payload.itemCount);
  });

  return <span className="badge">{count}</span>;
}

Example: Multiple listeners

import { useOn, Payload } from '@accelint/bus';

type AppEvents =
  | Payload<'user:login', { userId: string }>
  | Payload<'user:logout'>;

function AuthMonitor() {
  useOn<AppEvents, 'user:login'>('user:login', (event) => {
    console.log('Login:', event.payload.userId);
  });

  useOn<AppEvents, 'user:logout'>('user:logout', () => {
    console.log('Logout');
  });

  return null;
}

Good to know: The listener is automatically cleaned up when the component unmounts. The callback is stable and won't cause re-subscriptions when it changes.


useOnce

React hook to attach event bus listener with type-safe callback that executes only once.

Usage

import { useOnce, Payload } from '@accelint/bus';

type MyEvents = Payload<'user:login', { userId: string }>;

function FirstLoginDetector() {
  useOnce<MyEvents, 'user:login'>('user:login', (event) => {
    console.log('First login detected:', event.payload.userId);
  });

  return null;
}

Reference

function useOnce<
  Events extends BasicPayload,
  Type extends Events['type']
>(
  type: Type,
  callback: (data: ExtractEvent<Events, Type>) => void
): void

Parameters:

ParameterTypeDescription
typeType extends Events['type']Event type
callback(data: ExtractEvent<Events, Type>) => voidHandler that matches event type and receives corresponding payload

Type Parameters:

  • Events - Union of event types
  • Type - Type of event

Examples

Example: One-time initialization

import { useOnce, Payload } from '@accelint/bus';

type InitEvents = Payload<'app:ready'>;

function OnboardingTour() {
  const [show, setShow] = React.useState(false);

  useOnce<InitEvents, 'app:ready'>('app:ready', () => {
    setShow(true); // Only shows on first app:ready event
  });

  return show ? <div>Welcome!</div> : null;
}

Example: Feature flag activation

import { useOnce, Payload } from '@accelint/bus';

type FeatureEvents = Payload<'feature:enabled', { feature: string }>;

function FeatureDetector() {
  const [enabled, setEnabled] = React.useState(false);

  useOnce<FeatureEvents, 'feature:enabled'>('feature:enabled', (event) => {
    if (event.payload.feature === 'dark-mode') {
      setEnabled(true);
    }
  });

  return enabled ? <div>Dark mode available!</div> : null;
}

Good to know: The callback is only invoked for the first matching event after the component mounts. Subsequent events are ignored. The listener is cleaned up after firing or when the component unmounts.

  • Broadcast - Underlying event bus class
  • Payload - Type helper for defining events
  • EmitOptions - Options for controlling event delivery

On this page