Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

135
Vistas
Adapting an animated canvas element into a React component

I'm currently trying to convert a canvas element that has a looping animation into a React project as a component, and struggling to figure out the best way to adapt it over. I've been mainly using this article as a guide (https://medium.com/@pdx.lucasm/canvas-with-react-js-32e133c05258) and it looks like useRef() could be a good tool here but I'm struggling to figure out how to structure the component.

This is the code I'm attempting to convert:

var ctx = document.querySelector("canvas").getContext("2d"),
    dashLen = 220, dashOffset = dashLen, speed = 5,
    txt = "STROKE-ON CANVAS", x = 30, i = 0;

ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif"; 
ctx.lineWidth = 5; ctx.lineJoin = "round"; ctx.globalAlpha = 2/3;
ctx.strokeStyle = ctx.fillStyle = "#1f2f90";

(function loop() {
  ctx.clearRect(x, 0, 60, 150);
  ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
  dashOffset -= speed;                                         // reduce dash length
  ctx.strokeText(txt[i], x, 90);                               // stroke letter

  if (dashOffset > 0) requestAnimationFrame(loop);             // animate
  else {
    ctx.fillText(txt[i], x, 90);                               // fill final letter
    dashOffset = dashLen;                                      // prep next char
    x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
    ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random());        // random y-delta
    ctx.rotate(Math.random() * 0.005);                         // random rotation
    if (i < txt.length) requestAnimationFrame(loop);
  }
})();

<canvas width=630></canvas>

Really appreciate any advice

almost 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

There are certainly a lot of ways you could do this. Me personally, I wouldn't use ref. Ref is really only useful for functions that happen as a reaction to something (like clicking a button, changing a field's value).

Since we need the context, and want to set up a render loop, we'll want to be able to know when the canvas has been created. For this, we'll use useState and pass the setter to the canvas' ref property. The animation loop will setup inside an effect. We need to keep track of wether or not the component is still mounted, so we use a local variable in the effect to keep track of this (and if we're not mounted, we short-circuit the animation frame).

function CanvasComponent() {
  const [canvas, setCanvas] = React.useState();

  React.useEffect(() => {
    // On the first render, canvas won't be set. However, once setCanvas is called by ref, this effect will run again.
    if (canvas == null) return;
    const ctx = canvas.getContext("2d");
    const dashLen = 220;
    let dashOffset = dashLen;
    const speed = 5;
    const txt = "STROKE-ON CANVAS";
    let x = 30;
    let i = 0;

    ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif";
    ctx.lineWidth = 5;
    ctx.lineJoin = "round";
    ctx.globalAlpha = 2 / 3;
    ctx.strokeStyle = ctx.fillStyle = "#1f2f90";
    
    // Keep track of wether the component is still mounted
    let mounted = true;

    const loop = () => {
      if (!mounted) return;
      ctx.clearRect(x, 0, 60, 150);
      ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
      dashOffset -= speed; // reduce dash length
      ctx.strokeText(txt[i], x, 90); // stroke letter

      if (dashOffset > 0) requestAnimationFrame(loop); // animate
      else {
        ctx.fillText(txt[i], x, 90); // fill final letter
        dashOffset = dashLen; // prep next char
        x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
        ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random()); // random y-delta
        ctx.rotate(Math.random() * 0.005); // random rotation
        if (i < txt.length) requestAnimationFrame(loop);
      }
    };

    requestAnimationFrame(loop);
    
    // React will call this function when the effects' dependencies change, or the component is unmounted
    return () => {
      // Set mounted to false so that the next frame is short-circuited.
      mounted = false;
    };
  }, [canvas]);

  return <canvas width="630" ref={setCanvas}></canvas>;
}

Hope this helps.

P.S.

I don't know if it's intentional or not, but in your code, i is never updated.

almost 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda