@solid-primitives/event-bus
Version:
A collection of SolidJS primitives providing various features of a pubsub/event-emitter/event-bus.
302 lines (214 loc) • 7.71 kB
Markdown
<p>
<img width="100%" src="https://assets.solidjs.com/banner?type=Primitives&background=tiles&project=Event%20Bus" alt="Solid Primitives Event Bus">
</p>
# @solid-primitives/event-bus
[](https://bundlephobia.com/package/@solid-primitives/event-bus)
[](https://www.npmjs.com/package/@solid-primitives/event-bus)
[](https://github.com/solidjs-community/solid-primitives#contribution-process)
A collection of SolidJS primitives providing various features of a pubsub/event-emitter/event-bus:
- [`createEventBus`](#createeventbus) - Provides a simple way to listen to and emit events.
- [`createEmitter`](#createemitter) - Creates an emitter with which you can listen to and emit various events.
- [`createEventHub`](#createeventhub) - Provides helpers for using a group of buses.
- [`createEventStack`](#createeventstack) - Provides the emitted events as list/history, with tools to manage it.
## Installation
```bash
npm install @solid-primitives/event-bus
# or
pnpm add @solid-primitives/event-bus
# or
yarn add @solid-primitives/event-bus
```
## `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
```ts
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
```ts
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.
```ts
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
```ts
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
```ts
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.
```ts
hub.value.myBus;
// same as
hub.myBus.value();
```
## `createEventStack`
Extends [`createEmitter`](#createemitter). Provides the emitted events in a list/history form, with tools to manage it.
### How to use it
```ts
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.
```ts
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**.
```ts
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.
```ts
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.
```ts
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
https://codesandbox.io/s/solid-primitives-event-bus-6fp4h?file=/index.tsx
## Changelog
See [CHANGELOG.md](./CHANGELOG.md)