Skip to content

toggle

ts
toggle(subscribe: () => Unsubscribe): Toggle

Turns anything that returns its own unsubscribe function into a switch.

ts
interface Toggle {
  readonly isActive: boolean;
  start: () => void;
  stop: () => void;
}

start and stop are bound, so each is a callback as it is.

Usage

js
import { 
Base
,
toggle
,
useRaf
} from '@studiometa/js-toolkit';
class
SliderItem
extends
Base
{
static
config
= {
name
: 'SliderItem' };
#frame =
toggle
(() =>
useRaf
().
subscribe
(({
delta
}) => this.
follow
(
delta
)));
mounted
() {
// `stop` is bound, so it is a cleanup as it is. return this.#frame.
stop
;
}
follow
(
delta
) {}
onIndexChange
() {
this.#frame.
start
();
}
onSettled
() {
this.#frame.
stop
();
} }

start() is idempotent and stop() is safe to repeat.

What it works on

Anything whose subscribe call returns a release:

js
import { 
signal
,
toggle
,
useScroll
} from '@studiometa/js-toolkit';
const
count
=
signal
(0);
const
el
=
document
.
body
;
// a service
toggle
(() =>
useScroll
().
subscribe
(() => {}));
// a signal
toggle
(() =>
count
.
subscribe
(() => {}));
// a bare listener
toggle
(() => {
const
handler
= () => {};
el
.
addEventListener
('click',
handler
);
return () =>
el
.
removeEventListener
('click',
handler
);
});

It knows nothing about Base, so it works outside a component too.

Why it exists

The scheduler has no permanent rAF loop: it requests the next frame while a tick subscriber stays. So a component that needs the loop for part of a cycle should not hold a subscription for the whole cycle — and hand-rolling "unsubscribe if subscribed, and remember which" at every call site is the bug this removes.

{ manual: true } on a service mixin gives you the same object under $services.<hook>. See Mixins.

smoothTo() is a toggle() over useRaf(): one subscription however many times the target is set, started when the value has somewhere to go, released when it arrives.

MIT Licensed