Alpine: Using requestAnimationFrame in a component's function

Created on 1 Mar 2020  路  5Comments  路  Source: alpinejs/alpine

This is probably beyond the intended scope of Alpine, but if anyone can shed light on this problem I'd be grateful. I have a component:

<div x-data="foobar()" x-init="initialise()"></div>
function foobar() {
    return {
        run() {
            window.requestAnimationFrame(this.run);
            // do some animated stuff here
        },
        initialise() {
            this.run();
        }
    }
}

This produces the error:

TypeError: this is undefined

in reference to the line with requestAnimationFrame. Any idea whether this is possible with Alpine?

Most helpful comment

It would be something like

        run() {
           const that = this
           window.requestAnimationFrame(() => that.run())
        },

if you pass that.run(), you are not passing a callable but the result of that function, to calculate the result, the engine needs to execute run(), which calls requestAnimationFrame, which needs the result of that.run and so on.

If you need to support ie11, you can also use

        run() {
           const that = this
           window.requestAnimationFrame(function() {that.run()}) 
        },

or

        run() {
           window.requestAnimationFrame(function() {this.run()}.bind(this)) 
        },
run() {
    // Do stuff
    requestAnimationFrame(() => this.run())
})

Is enough

All 5 comments

Yeah, it's normal javascript at that point. The context of the callback is not the object so you can't use this but you can do const self = this at the beginning of the run function and then you should be able to use self.run() in your requestAnimationFrame callback.

Thanks @SimoTod - I should have said I've tried that, i.e.:

run() {
    let that = this;
    window.requestAnimationFrame(that.run);
}

produces the error

TypeError: that is undefined

and if I try:

window.requestAnimationFrame(that.run());

I get a "too much recursion" error...

It would be something like

        run() {
           const that = this
           window.requestAnimationFrame(() => that.run())
        },

if you pass that.run(), you are not passing a callable but the result of that function, to calculate the result, the engine needs to execute run(), which calls requestAnimationFrame, which needs the result of that.run and so on.

If you need to support ie11, you can also use

        run() {
           const that = this
           window.requestAnimationFrame(function() {that.run()}) 
        },

or

        run() {
           window.requestAnimationFrame(function() {this.run()}.bind(this)) 
        },

Gah of course. Thanks for the advice, it's working now.

It would be something like

        run() {
           const that = this
           window.requestAnimationFrame(() => that.run())
        },

if you pass that.run(), you are not passing a callable but the result of that function, to calculate the result, the engine needs to execute run(), which calls requestAnimationFrame, which needs the result of that.run and so on.

If you need to support ie11, you can also use

        run() {
           const that = this
           window.requestAnimationFrame(function() {that.run()}) 
        },

or

        run() {
           window.requestAnimationFrame(function() {this.run()}.bind(this)) 
        },
run() {
    // Do stuff
    requestAnimationFrame(() => this.run())
})

Is enough

Was this page helpful?
0 / 5 - 0 ratings