Andre Pena
Andre Pena

Reputation: 59336

ReactJs: How to recover from errors in a child component?

I'm building a live code editor for my library and, because of that, some components may trigger an exception while rendering due to invalid input. That's a completely expected behavior.

My problem now is that the entire page crashes when the input is invalid.

What I wanted was a way to catch the exception and show a red alert where the component should be. Again, it's a live code editor, things are expected to break.

I can't find a way around this. Any idea?

Upvotes: 3

Views: 1399

Answers (2)

Ben Mosher
Ben Mosher

Reputation: 13381

IME, every render() implementation must properly handle exceptions while building its component subtree.

Due to the way React buffers DOM updates, though, the sub-components are not render-ed deeper in the stack, it's more like:

class Main extends React.Component {
  render() { return <div className="wrapper"><Child question={think()} /></div> }
}

class Child extends React.Component {
  render() { return <div className="child-stuff" /> }
}

React.render(<Main answer={42} />, document.getElementById('reactRoot'))

..will call Main#render, which will then queue Child.render for execution, then execute it either later on the event loop, or on the next tick, etc.

This async execution means you can only reliably catch exceptions in a #render method for the code it executes directly (think()), but not what the child component's #render does.

I believe this precludes higher-order components from handling arbitrary exceptions (i.e. program/data errors), though I agree with Filip that this is otherwise a great answer for general (predictable) error handling.

See React #2461 for more details, but I believe this is the current state of things.

Upvotes: 1

Filip Dupanović
Filip Dupanović

Reputation: 33650

A good point where you can interject is when your creating React elements, via React.render, React.createElement, React.cloneElement:

try {
  React.render(<Editor />, container);
} catch (e) {
  // Something went wrong. Let's recover.
  React.render(<ItsNotMeItsYourComputer />, container);
}

So doing something like this in a global context would help you recover when creating and mounting your editor in the DOM. For better control, however, you would probably want to write either higher-order components or custom controller views which have a specific way of how they create and manage child components, with the added ability to render a generic Error view in case things go wrong.

Upvotes: 0

Related Questions