1

I'm having a hard time understanding how this works inside an onClick function. I made a small CodePen example here.

const history = {
  init() {
    this.counter = 0

    return this;
  },

  increment() {
    this.counter++;
  }
}

const a = Object.create(history).init()

const MyComponent = () => {

  a.increment();

  // a's context is lost in the onClick function, how to
  // make this work?

  return (
    <>

      <button onClick={a.increment}>
        click to increment
      </button>
    <p>{a.counter}</p>
      </>
  )
}

I realize this context is call-site specific, and it rebinds to the onClick function and thus the context i need to make it work is lost. But i don't know how to fix that. I realize i could use lambda syntax or refactor the object another way that avoids this completely, but that would just be dodging the problem.

Anyone able to provide a solution and a quick answer of what is really going on?

Md. Sabbir Ahmed
  • 578
  • 5
  • 15
  • Does this answer your question? [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Yury Tarabanko Dec 13 '19 at 13:26
  • "would just be dodging the problem" no it is not. You need to create a new function that is binded to the context you want. When and how exactly to do it is up to you. – Yury Tarabanko Dec 13 '19 at 13:27
  • Also you are creating a new instance of `a` on every call. Not to say that mutating some external object wont cause your component to rerender. So even if you fix the context issue your code wont update counter value on a screen. – Yury Tarabanko Dec 13 '19 at 13:30
  • You are right, code has been changed. But im still not sure how to make this work – Flimzy_Programmer Dec 13 '19 at 13:38

1 Answers1

2

You can set value of this inside increment function using bind function. You also need to update state of the component to re-render it.

Code

const history = {
  init() {
    this.counter = 0;
    return this;
  }, 

  increment(setCounter) {
    setCounter(++this.counter);
  }
}

const a = Object.create(history).init();

const MyComponent = () => {
  const [counter, setCounter] = useState(a.counter);  

  return (
    <>
      <button onClick={a.increment.bind(a, setCounter)}>
        click to increment
      </button>
      <p>{a.counter}</p>
    </>
  )
};

See working example

Yousaf
  • 20,803
  • 4
  • 23
  • 45