OlehZiniak
OlehZiniak

Reputation: 953

Bind this when using method decorators in React

How to bind this with transform-decorators-legacy Babel plugin? For example I have some simple decorator. Decorator works, but this is undefined on component's method.

fucntion myDecorator(target, name, descriptor) {
    var oldValue = descriptor.value;

    descriptor.value = function() {
        ...// Doing some stuff here I need the decorator for
        ...// (for example logging on every method call)
        return oldValue.apply(null, arguments);
    };

    return descriptor;

}

class MyClass extends React.Component {
    @myDecorator
    myMethod() {
        ...// this.props... is unavailable here(`this` is undefined)
    }
}

If I try to use @myDecorator with some @autobind decorators I get TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, because

A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.

In my example I can not use value() and get().

Binding in the constructor (this.myMethod = thid.myMethod.bind(this)) doesn't seem to be helpful either, because you bind undecorated method.

Upvotes: 1

Views: 4606

Answers (2)

yadhu
yadhu

Reputation: 15642

Is it not the problem with .binding decorated methods.

But there is something that you missed. Even though you did .bind your myMethod inside your constructor to the class, when you invoke it, no matter from where, myDecorator modifies the execution scope.

oldValue.apply(null, arguments)

Basically, you replaced target scope (MyClass) with null.

So what you want is this:

oldValue.apply(this, arguments)

See this fiddle: http://jsfiddle.net/free_soul/0n6v1dtp/

Upvotes: 2

OlehZiniak
OlehZiniak

Reputation: 953

This is how I managed to solve this: Using code from mentioned @autobind decorator:

function myDecorator(target, key, descriptor) {
    let fn = descriptor.value;

    return {
        configurable: true,

        get() {
            let boundFn = fn.bind(this);
            Reflect.defineProperty(this, key, {
                value: boundFn,
                configurable: true,
                writable: true
            });

            return function() {
                ...// Doing some stuff here I need the decorator for
                ...// (for example logging on every method call)
                return boundFn.apply(this, arguments)
            };
        }
    };
}

Upvotes: 2

Related Questions