3

I came accross a weird behavior. See this fiddle. When using React 16 error handling mechanisme, namely Error Boundary, I noticed the error parameter was empty. Upon further investigation I realised it was only the case when throwing an Error object like so :

throw new Error('The world is very strange')

However, when throwing the error this way :

throw 'The world is very strange'

The error will be available in componentDidCatch.

Please, someone, enlighten me. I wish to continue using new Error because it is recommended to use it and it should give access to file and line number of throw.

Let's take a look at the code.

class Boundary extends React.Component {
    constructor() {
      super();
      this.state = {}
    }

    componentDidCatch(error, info) {
       this.setState({
        error,
        info,
      })
    }

  render() {
    if (this.state.error) {
       return (
       <div>
         {JSON.stringify(this.state)}
       </div>)
    }
    return this.props.children;
   }
}

class Component extends React.Component {
    render() {
  // Why and what should i do ?
    throw 'This will be available in the error parameter'
    throw new Error('This one will not')
  }
}

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
    <Boundary>
      <div>
        <Component />
      </div>
    </Boundary>
    )
  }
}
Arro
  • 158
  • 1
  • 10
  • 1
    Please, update the question with relevant code from your fiddle. Links may become dead, while the question should be understandable without reading external resources. – Estus Flask Jul 17 '18 at 15:09

2 Answers2

5

The error is actually available. The problem is that JSON.stringify doesn't serialize Error objects, and since that's what you're using to display the error, it appears like the error is empty.

Here's an updated version of your fiddle that explicitly outputs state.error.message, and it works.

balpha
  • 50,022
  • 18
  • 110
  • 131
2

Throwing strings is discouraged because an error is conventionally an object, preferably an instance of Error.

There is no problem with throwing Error. There is a problem with how it's processed:

  if (this.state.error) {
     return (
     <div>
       {JSON.stringify(this.state)}
     </div>)
  }

Since error.message is non-enumerable, error is stringified to {}. This is expected behaviour. JSON.stringify shouldn't be relied on as all-round representation of objects - this is what dev tools console is for.

Current representation could be fixed by extending Error:

class HumanReadableError extends Error {
  toJSON() {
    return `Error: ${this.message}`;
  }
}

and

throw new HumanReadableError('This will not be available');
Estus Flask
  • 206,104
  • 70
  • 425
  • 565