Event Bus

NPM
v1.0.8

#Installation

npm install @solid-primitives/event-bus
yarn add @solid-primitives/event-bus
pnpm add @solid-primitives/event-bus

#Readme

A collection of SolidJS primitives providing various features of a pubsub/event-emitter/event-bus:

  • createEventBus - Provides a simple way to listen to and emit events.
  • createEmitter - Creates an emitter with which you can listen to and emit various events.
  • createEventHub - Provides helpers for using a group of buses.
  • createEventStack - Provides the emitted events as list/history, with tools to manage it.

#createEventBus

Provides all the base functions of an event-emitter, plus additional functions for managing listeners, it's behavior could be customized with an config object. Good for advanced usage.

#How to use it

import { createEventBus } from "@solid-primitives/event-bus";

const bus = createEventBus<string>();

// can be used without payload type, if you don't want to send any
createEventBus();

// bus can be destructured:
const { listen, emit, clear } = bus;

const unsub = bus.listen(a => console.log(a));

bus.emit("foo");

// unsub gets called automatically on cleanup
unsub();

#createEmitter

Creates an emitter with which you can listen to and emit various events.

#How to use it

import { createEmitter } from "@solid-primitives/event-bus";

const emitter = createEmitter<{
  foo: number;
  bar: string;
}>();
// can be destructured
const { on, emit, clear } = emitter;

emitter.on("foo", e => {});
emitter.on("bar", e => {});

emitter.emit("foo", 0);
emitter.emit("bar", "hello");

// unsub gets called automatically on cleanup
unsub();

#createGlobalEmitter

Wrapper around createEmitter.

Creates an emitter with which you can listen to and emit various events. With this emitter you can also listen to all events.

import { createGlobalEmitter } from "@solid-primitives/event-bus";

const emitter = createGlobalEmitter<{
  foo: number;
  bar: string;
}>();
// can be destructured
const { on, emit, clear, listen } = emitter;

emitter.on("foo", e => {});
emitter.on("bar", e => {});

emitter.emit("foo", 0);
emitter.emit("bar", "hello");

// global listener - listens to all channels
emitter.listen(e => {
  switch (e.name) {
    case "foo": {
      e.details;
      break;
    }
    case "bar": {
      e.details;
      break;
    }
  }
});

#createEventHub

Provides helpers for using a group of event buses.

Can be used with createEventBus, createEventStack or any emitter that has the same api.

#How to use it

#Creating EventHub

import { createEventHub } from "@solid-primitives/event-bus";

// by passing an record of Channels
const hub = createEventHub({
  busA: createEventBus(),
  busB: createEventBus<string>(),
  busC: createEventStack<{ text: string }>(),
});

// by passing a function
const hub = createEventHub(bus => ({
  busA: bus<number>(),
  busB: bus<string>(),
  busC: createEventStack<{ text: string }>(),
}));

// hub can be destructured
const { busA, busB, on, emit, listen, value } = hub;

#Listening & Emitting

const hub = createEventHub({
  busA: createEventBus<void>(),
  busB: createEventBus<string>(),
  busC: createEventStack<{ text: string }>(),
});
// can be destructured
const { busA, busB, on, listen, emit } = hub;

hub.on("busA", e => {});
hub.on("busB", e => {});

hub.emit("busA", 0);
hub.emit("busB", "foo");

// global listener - listens to all channels
hub.listen(e => {
  switch (e.name) {
    case "busA": {
      e.details;
      break;
    }
    case "busB": {
      e.details;
      break;
    }
  }
});

#Accessing values

If a emitter returns an accessor value, it will be available in a .value store.

hub.value.myBus;
// same as
hub.myBus.value();

#createEventStack

Extends createEmitter. Provides the emitted events in a list/history form, with tools to manage it.

#How to use it

import { createEventStack } from "@solid-primitives/event-bus";

const bus = createEventStack<string, { message: string }>({
  // toValue parsing function is optional
  toValue: e => ({ message: e })
});
// can be destructured:
const { listen, emit, clear, value } = bus;

const listener: EventStackListener<{ text: string }> = ({ event, stack, remove }) => {
  console.log(event, stack);
  // you can remove the value from stack
  remove();
};
bus.listen(listener);

bus.emit({ text: "foo" });

// a signal accessor:
bus.value() // => { text: string }[]

bus.setValue(stack => stack.filter(item => {...}))

#EventBus Utils

#toPromise

Turns a stream-like listen function, into a promise resolving when the first event is captured.

import { toPromise } from "@solid-primitives/event-bus";

const emitter = createEmitter<string>();
const event = await toPromise(emitter.listen);

// can be used together with raceTimeout from @solid-primitives/utils
import { raceTimeout } from "@solid-primitives/utils";
try {
  const event = await raceTimeout(toPromise(emitter.listen), 2000, true, "event was too slow");
  // if event is quicker:
  event; // => string
} catch (err) {
  // if timeouts:
  console.log(err); // => "event was too slow"
}

#once

Listen to any EventBus/Emitter, but the listener will automatically unsubscribe on the first captured event. So the callback will run only once.

import { once } from "@solid-primitives/event-bus";

const { listen, emit } = createEmitter<string>();
const unsub = once(listen, event => console.log(event));

emit("foo"); // will log "foo" and unsub

emit("bar"); // won't log

#toEffect

Wraps emit calls inside a createEffect. It causes that listeners execute having an reactive owner available. It allows for usage of effects, memos and other primitives inside listeners, without having to create a synthetic root.

import { toEffect } from "@solid-primitives/event-bus";

const { listen, emit } = createEmitter();
const emitInEffect = toEffect(emit);

// owner is needed for creating computations like createEffect
listen(() => console.log(getOwner()));

// ...sometime later (after root initiation):
emit(); // listener will log `null`
emitInEffect(); // listener will log an owner object

#batchEmits

Wraps emit calls inside a batch call. It causes that listeners execute in a single batch, so they are not executed in sepatate queue ticks.

import { createEventBus, batchEmits } from "@solid-primitives/event-bus";

const bus = batchEmits(createEventBus());

const [a, setA] = createSignal(0);
const [b, setB] = createSignal(0);

bus.listen(setA);
bus.listen(setB);

bus.emit(1); // will set both a and b to 1 in a single batch

#Demo

Live Site

CodeSandbox

#Changelog

See CHANGELOG.md