Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrow functions on class do not work. #6

Open
seivan opened this issue May 18, 2022 · 1 comment
Open

Arrow functions on class do not work. #6

seivan opened this issue May 18, 2022 · 1 comment
Labels
documentation Improvements or additions to documentation

Comments

@seivan
Copy link

seivan commented May 18, 2022

Assume this code

class CounterState {  // Your State
    value = 0;  
    increment () {this.value +=1 }
}

const state = observable({ 
    counter: new CounterState()
});

const Counter = observer(function Counter({counter} : {counter : CounterState}) {
    const {value, increment} = counter;
    return (
        <div>
            <span>Count: {value}</span>
            <button onClick={increment}>Increment</button>
        </div>
    );
});

function App () {
    return (
        <Counter counter={state.counter}/>
    );
}

If you change to
increment () {this.value += 1}
to
increment = () => {this.value +=1}

It will no longer trigger updates.

I'm no expert, but isn't it better that arrow functions work since you've always expecting to get the correct this, especially in a class.

@selsamman
Copy link
Owner

For the proxying needed to support observable behavior all references to objects must stem from the object that is returned from observable. The object returned is a Proxy. At the time the object is made observable, observable behavior is cascaded to all referenced properties by making them a Proxy. This is why when modifying data in the constructor observable behavior is extended to the modified properties.

In the case of a normal method "this" would be bound to the object when referenced as object.method. Proxily goes further by binding the method to the proxied object so you can use it without the object.method notation. In the case of an arrow function, "this" is not bound to the object but rather assumes the value it had during the course of execution of the constructor. Since the constructor of the class is executed before the object is made observable "this" will have the value of the original object rather than the proxied object. Therefore it won't have observable behavior.

As to whether or not it is "better" to use arrow functions rather than normal methods I suppose it is a matter of opinion. Arrow functions inside class methods are essential to ensuring that "this" will inherit it's value from the method itself. These, however, are normally local functions within the method. Exposing the arrow function outside of the method as would be the case when assigning it to a property and using it in place of a method is a very different use-case in my view. I am not sure there are any advantages of using arrow function properties over normal class methods. Also normal class methods are attached to the prototype so they don't have to be created for each instance.

In any event you have identified that there are some things in the "magic" of cascading observable behavior that may not be obvious and I will attempt to address this in the documentation as any user of the library would rightfully perceive this issue as a "gotcha". Again thanks for taking the time to kick the tires on Proxily and write up your findings.

@selsamman selsamman added the documentation Improvements or additions to documentation label May 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants