Search code examples
reactjsonclickthiscodepen

Understanding "this" context in onClick handler


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?


Solution

  • 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