Skip to content

useRaf

ts
useRaf(): Service<RafProps, void | RafRender>

The frame clock as a service. It has nothing to scope, so there is one instance.

Props

ts
interface RafProps {
  readonly time: DOMHighResTimeStamp;
  readonly delta: number;
}

delta is clamped to [1, 40] ms, and the first tick after the loop wakes reports 1000/60. time stays the raw rAF timestamp.

Usage

js
import { 
Base
,
useRaf
} from '@studiometa/js-toolkit';
class
Ticker
extends
Base
{
static
config
= {
name
: 'Ticker' };
mounted
() {
return
useRaf
().
subscribe
(({
delta
}) => {
// … }); } }

A callback can return a render function

useRaf is the one service whose callback return value is used. Return a function and it runs in the frame's write phase:

js
import { 
Base
,
useRaf
} from '@studiometa/js-toolkit';
class
Follower
extends
Base
{
static
config
= {
name
: 'Follower' };
mounted
() {
return
useRaf
().
subscribe
(({
delta
}) => {
const
x
= this.
$el
.
offsetLeft
+
delta
;
return () => { this.
$el
.
style
.
transform
= `translateX(${
x
}px)`;
}; }); } }

The service collects the render functions of its callbacks and cancels a render whose subscriber left between the two phases.

It does not own a loop

It subscribes to scheduler.tick(). The scheduler requests the next frame while a tick subscriber stays, so there is no permanent rAF loop and no loop of the service's own.

{ immediate: true } does nothing here: the frame tick has no current value between two frames, which is what its hasProps() says.

Switching it on and off

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
() {
return this.#frame.
stop
;
}
follow
(
delta
) {}
}

See toggle(), and withRaf(Base, { manual: true }) in Mixins.

Mixin

js
class Follower extends withRaf(Base) {
  ticked({ delta }) {}
}

MIT Licensed