How to use requestAnimationFrame with a TypeScript object?

Ian Boyd picture Ian Boyd · Feb 21, 2014 · Viewed 9.8k times · Source

I have an object that i want to do drawing on a canvas. It will use requestAnimationFrame to start a game loop:

Contoso.ts

class Contoso
{
   //private ctx: CanvasRenderingContext2D;

   Initialize(ctx: CanvasRenderingContext2D) {
      //this.ctx = ctx;
      Render();
   }

   Render() {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(this.Render);
   }
}

app.ts

var contoso: Contoso;

contoso = new Contoso();
contoso.Initialize(canvas);

The first time someone calls Initialize, the requestAnimationFrame manages to correctly call Render.

The second time requestAnimationFrame calls Render, the this.Render is undefined and it crashes.

It's almost as though the object was destroyed after the initial call to Initialize.

What is going on?

Answer

Ryan Cavanaugh picture Ryan Cavanaugh · Feb 21, 2014

You've lost this context. Two possible fixes:

class Contoso
{
   /* ... */

   // Use () => syntax so Render always gets 'this' context
   // from the class instance
   Render = () => {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(this.Render);
   }
}

The alternate fix is probably slightly clearer, but has the downside of making a lot more allocations (you probably don't want to allocate 1 closure per frame!)

   Render() {
      //...snip doing any actual drawing for the purpose of this question
      requestAnimationFrame(() => this.Render);
   }