Soundorv0.13.0

useAnimationFrame

A callback before every frame, while the component is mounted.

function useAnimationFrame(callback: (time: number) => void): void;

useAnimationFrame((time) => …) calls the callback before every frame the view draws, while the component is mounted, with the frame's time in milliseconds. It always calls the latest callback, so the callback may read the component's props and state.

import { Canvas, useAnimationFrame, useParameter } from '@soundor/react';
import { useRef } from 'react';
import { parameters } from 'soundor:parameters';
import type { UiNode } from 'soundor:ui';

const WIDTH = 320;
const HEIGHT = 120;

// A canvas drawn every frame: a wave as tall as the gain parameter.
export default function Wave() {
  const canvas = useRef<UiNode>(null);
  const gain = useParameter(parameters.gain);

  useAnimationFrame((time) => {
    const context = canvas.current?.getContext('2d');
    if (!context) return;
    context.fillStyle = '#17181c';
    context.fillRect(0, 0, WIDTH, HEIGHT);
    context.strokeStyle = '#3a7bfd';
    context.lineWidth = 2;
    context.beginPath();
    for (let x = 0; x <= WIDTH; x += 2) {
      const phase = x / 24 - time / 300;
      const y = HEIGHT / 2 - Math.sin(phase) * gain * (HEIGHT / 2 - 4);
      if (x === 0) context.moveTo(x, y);
      else context.lineTo(x, y);
    }
    context.stroke();
  });

  return (
    <Canvas
      ref={canvas}
      width={WIDTH}
      height={HEIGHT}
      style={{ borderRadius: 8 }}
    />
  );
}
canvas.tsxSource
  • Draw a Canvas with it: get the context from the canvas's ref and draw the frame. Drawing marks only the canvas as changed.
  • Not for animating styles: an Animated.View animates opacity and transforms in the runtime, without running JavaScript every frame.
  • Not for state: setting React state every frame re-renders the component every frame. Read values in the callback and draw instead.

It is requestAnimationFrame(), the global, in a hook: the callback runs once per frame, before the view is drawn, and stops when the component unmounts.