0

This is a simple React app that I just generated with create-react-app, and modified only App.js to what you see below. This is an exercise to see if I understand bind enough to get results I expect as I toy with it. I'm not getting the expected result: I bind method in the class to obj, and use an onClick on a div to execute this bound method. In the method definition, I am calling this.setState, and setState is defined on obj, but I get an error that this.state is undefined in the setState method definition. Why?


import React from 'react';
import './App.css';

const Button = ({ onClick, quantity }) => <div onClick={onClick} style={{ width: 40 , height: 20}}>{quantity}</div>;

const generateButton = (quantity, onClick) => () => <Button onClick={() => onClick(quantity)} quantity={quantity} />

const obj = {
 state: { count: 1000 }, 
setState: ({ count }) => this.state.count += count
};

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }

    this.method = this.method.bind(obj);
  }

  method(count) {
    const newCount = this.state.count + count;
    this.setState({ count: newCount})
  }

  render() {
    return (
        <div>
            <div style={{width: 100, height: 100, fontSize: 50}}>{obj.state.count}</div>
            {generateButton(10, this.method)()}
        </div>
    )
  }
}

export default App;

Error in browser

evianpring
  • 3,316
  • 1
  • 25
  • 54
  • Is there a reason you put the state object outside of your class? – EDToaster Jul 10 '19 at 20:47
  • @JClassic I ran into an unexpected issue using bind with another library (React-Data-Grid), so I built this example just to test my understanding of bind. It's not meant to be anything except to ascertain how bind is working. – evianpring Jul 10 '19 at 20:48
  • 1
    You're using an arrow function which doesn't have its own context, but uses `this` which refers to the parent context here, which isn't defined since at the root of the file. – Emile Bergeron Jul 10 '19 at 20:49
  • 1
    Using a `function () {}` expression would "work" but that would be confusing as hell since you named these the same as React's component's api, but it's not and won't trigger the lifecycle of React. – Emile Bergeron Jul 10 '19 at 20:51

1 Answers1

3

When you use arrow functions, the context is taken from the nearest scope in which the function is defined. In your case, this would refer to the module scope.

From the docs

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope, an arrow function ends up finding the this from its enclosing scope.

If you want the scope to remain relative to the object then use a standard function definition

setState: function({ count }) {
  this.state.count += count;
}
James
  • 80,725
  • 18
  • 167
  • 237
  • Ok, that was an easy miss on my part. I'm going to post a question that is the actual issue I am having and will link here. – evianpring Jul 10 '19 at 20:55
  • The real-life question that inspired this question: https://stackoverflow.com/questions/56978862/how-does-a-react-method-bound-in-constructor-lose-its-boundedness-in-this-examp – evianpring Jul 10 '19 at 21:29