An error boundary catches renders and not event handlers

An error boundary catches errors thrown during rendering, in lifecycle methods and in constructors, and nothing thrown from a click handler or a promise.

class Boundary extends React.Component {
  static getDerivedStateFromError() { return { failed: true } }
  componentDidCatch(error, info) { report(error, info) }
  render() { return this.state.failed ? <Fallback /> : this.props.children }
}

// not caught:
//   onClick={() => { throw new Error() }}
//   an unhandled promise rejection
//   anything in setTimeout
//   errors thrown during server rendering

Handlers and promises need their own try or a global handler, which means an application relying only on boundaries has coverage for the minority of its failures. In 18 an uncaught error also unmounts the whole tree rather than leaving a broken component in place, so a boundary is now closer to required than optional.