Star

Created With

Callbags


Callbags represent values that change over time:

1linkimport { interval, pipe, map, filter, subscribe } from 'callbag-common'; // @see [callbag-common](https://loreanvictor.github.io/callbag-common/)

2link

3linkconst source = interval(1000); // --> emits every second

4linkpipe(

5link source,

6link map(x => x * 3), // --> multiply by 3

7link filter(x => x % 2), // --> only allow odd numbers

8link subscribe(console.log) // --> log any incoming number

9link);

3 9 15 21 27
Playgound

👉 If you are familiar with RxJS, you can think of callbags as light-weight observables.
👉 Checkout this post for a more depth introduction to callbags.

local_library CALLBAG LIBRARIES

There are many callbag libraries you can use with callbag-jsx. For examples in this documentation, we are going to use callbag-common, which includes a nice set of commonly used callbag utilities and is also installed on the starter templates.




linkCreating Callbags

You can create callbag sources using states, using a source factory, or expressions of other callbags:

1linkimport { state } from 'callbag-state';

2linkimport { interval, fromEvent, expr } from 'callbag-common';

3link

4link

5link// a simple counter whose value we manually control:

6linkconst count = state(0);

7link

8link// a timer emitting every second:

9linkconst timer = interval(1000);

10link

11link// this will be the latest mouse event when mouse is moved:

12linkconst mouseEvent = fromEvent(document.body, 'mousemove');

13link

14link// a computed value based on count and timer:

15linkconst computed = expr($ => $(count) * $(timer));

16link

17link// a the X-axis of the mouse:

18linkconst mouseX = expr($ => $(mouseEvent).clientX);

👉 These callbags can now be embedded in DOM to make it change over time as well:

1linkrenderer.render(

2link <div style='height: 100vh'>

3link count: {count}

4link &emsp;

5link <span onclick={() => count.set(count.get() - 1)}>⬇️</span>

6link <span onclick={() => count.set(count.get() + 1)}>⬆️</span>

7link <br/>

8link

9link timer: {timer} <br/>

10link timer * count: {computed} <br/>

11link mouseX: {mouseX} <br/>

12link </div>

13link).on(document.body);

Playground



linkTransforming Callbags

You can pipe callbag sources to callbag operators to create new, modified callbags:

1linkimport { state } from 'callbag-state';

2linkimport { pipe, map, debounce } from 'callbag-common';

3link

4linkconst input = state('');

5linkconst len = pipe(

6link input,

7link debounce(200), // --> wait 200 milliseconds after last input change

8link map(s => s.length) // --> map it to its length

9link);

10link

11linkrenderer.render(

12link <>

13link <input _state={input} type='text' placeholder='Type something ...'/>

14link <br/>

15link Input Length: {len}

16link </>

17link).on(document.body);

Playground

local_bar PIPELINE OPERATOR

If you are using the JavaScript Starter Template, or Pipeline Operator Plugin for Babel, you can pipe callbags with the pipeline operator (|>) instead of the pipe() utility:

1linkconst len = input |> debounce(200) |> map(s => s.length)




linkSubscribing to Callbags

Typically you need to subscribe to callbag sources (i.e. listen to them). In callbag-jsx this is done implicitly when you embed callbags in DOM elements:

1linkconst s = state(0);

2linkrenderer.render(<div>{s}</div>).on(document.body);

👉 The subscription only happens AFTER the element is appended to main document:

1linkconst s = state(0);

2linkconst d = <div>{s}</div>; // --> no subscription

3linkrenderer.render(d).on(document.body); // --> subscription happens here

👉 The subscription is cleared when the element is removed from the main document:

1linkconst s = state(0);

2linkconst d = <div>{s}</div>; // --> no subscription

3linkrenderer.render(d).on(document.body); // --> subscription happens here

4link

5linkrenderer.render(

6link <button onclick={() => renderer.remove(d)}>Remove</button> {/* --> subscription ends when this button is clicked */}

7link).on(document.body);

⚠️ IMPORTANT ⚠️

You MUST use renderer.remove() method to ensure that the subscriptions of a DOM element are cleared. Otherwise, this might result in a memory leak as subscription resources are not released.


You can also explicitly subscribe to callbags, using subscribe() utility:

1linkimport { pipe, subscribe } from 'callbag-common';

2linkimport { state } from 'callbag-state';

3link

4linkconst s = state(0);

5linkpipe(s, subscribe(console.log)); // --> logs changes in value of s

👉 Remember to clear manual subscriptions when you no longer need them:

1linkimport { pipe, subscribe } from 'callbag-common';

2linkimport { state } from 'callbag-state';

3link

4linkconst s = state(0);

5linkconst clear = pipe(s, subscribe(console.log));

6link

7link// when everything is done:

8linkclear();





Creating CallbagsTransforming CallbagsSubscribing to Callbags

Home Getting Started


Introductionchevron_right

Basicschevron_right

Reactivitychevron_right

Componentschevron_right

In-Depthchevron_right

Metachevron_right