Interactivity in React

Explore how user interactions work in React using events.

Binding event handlers

Class component methods lose this when passed as DOM callbacks. Here are all the approaches.

🀷broken

No binding

this is undefined inside the handler when invoked by the DOM event system in strict mode.

0
class Counter extends Component {
  handleClick() {
    // this = undefined ❌
    this.setState(...)
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        +
      </button>
    )
  }
}
βœ“ constructor bind

Bind in constructor

Bound once at mount. No extra function created per render. Explicit and classic.

0
constructor(props) {
  super(props)
  this.state = { count: 0 }
  this.handleClick =
    this.handleClick.bind(this) // βœ“
}

handleClick() {
  this.setState(s =>
    ({ count: s.count + 1 })
  )
}
βœ“ class field

Class field arrow

Arrow functions capture this lexically. No constructor or explicit bind needed.

0
class Counter extends Component {
  state = { count: 0 }

  // Arrow captures this βœ“
  handleClick = () => {
    this.setState(s =>
      ({ count: s.count + 1 })
    )
  }
}
β˜… recommended

Function component + hooks

No this, no binding. Closures capture state directly. The modern default.

0
function Counter() {
  const [count, setCount] =
    useState(0)

  const handleClick = () => {
    setCount(c => c + 1) // βœ“
  }

  return (
    <button onClick={handleClick}>
      +
    </button>
  )
}

Event flow control

Events travel down (capture) then up (bubble). Select a mode to see each control method live.

Live demo

Outer div

Middle div

Click the button. The event fires at the target then bubbles up: Inner β†’ Middle β†’ Outer.

Event log

Interact with the demo above...

Code

<div onClick={() => log('Outer')}>
  <div onClick={() => log('Middle')}>
    <button
      onClick={() => log('Inner')}
    >
      Click
    </button>
  </div>
</div>

// Fires: Inner β†’ Middle β†’ Outer