简体   繁体   中英

React. Error info does not display after crash in the DOM

I make a simple test to catch an errors from MyComponent component, but after crashing the Error info does not showed in the DOM, instead it described in the code below. In the console it showed normaly.

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import './index.css';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      counter: 0,
      error: null,
      errorInfo: null
    };
  }

  handleClick = () => {
    this.setState({ counter: this.state.counter + 1 })
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ 
      error: true,
      errorInfo: errorInfo
    });

  }

  render() {
    if (this.state.counter > 5) {
      throw new Error('Ooops!');
      return(
        <React.Fragment> // this is were Error must displayed 
        <div>{this.state.error.toString()}</div>
        <div>{this.state.errorInfo.componentStack}</div>
        </React.Fragment>
      );
    }
    return <div style={{cursor: 'pointer'}} onClick={this.handleClick}>Click Me: {this.state.counter}</div>
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementById('root')
);

//// Errors Log in console:

    Uncaught Error: Ooops!
    at MyComponent.render (index.js:30)
    at finishClassComponent (react-dom.development.js:7873)
    at updateClassComponent (react-dom.development.js:7850)
    at beginWork (react-dom.development.js:8225)
    at performUnitOfWork (react-dom.development.js:10224)
    at workLoop (react-dom.development.js:10288)
    at HTMLUnknownElement.callCallback (react-dom.development.js:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
    at invokeGuardedCallback (react-dom.development.js:438)
    at renderRoot (react-dom.development.js:10366)
    at performWorkOnRoot (react-dom.development.js:11014)
    at performWork (react-dom.development.js:10967)
    at batchedUpdates (react-dom.development.js:11086)
    at batchedUpdates (react-dom.development.js:2330)
    at dispatchEvent (react-dom.development.js:3421)
render @ index.js:30
finishClassComponent @ react-dom.development.js:7873
updateClassComponent @ react-dom.development.js:7850
beginWork @ react-dom.development.js:8225
performUnitOfWork @ react-dom.development.js:10224
workLoop @ react-dom.development.js:10288
callCallback @ react-dom.development.js:542
invokeGuardedCallbackDev @ react-dom.development.js:581
invokeGuardedCallback @ react-dom.development.js:438
renderRoot @ react-dom.development.js:10366
performWorkOnRoot @ react-dom.development.js:11014
performWork @ react-dom.development.js:10967
batchedUpdates @ react-dom.development.js:11086
batchedUpdates @ react-dom.development.js:2330
dispatchEvent @ react-dom.development.js:3421
index.js:2178 The above error occurred in the <MyComponent> component:
    in MyComponent (at index.js:43)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit s to learn more about error boundaries.
__stack_frame_overlay_proxy_console__ @ index.js:2178
logCapturedError @ react-dom.development.js:9747
captureError @ react-dom.development.js:10540
renderRoot @ react-dom.development.js:10391
performWorkOnRoot @ react-dom.development.js:11014
performWork @ react-dom.development.js:10967
batchedUpdates @ react-dom.development.js:11086
batchedUpdates @ react-dom.development.js:2330
dispatchEvent @ react-dom.development.js:3421
index.js:30 Uncaught Error: Ooops!
    at MyComponent.render (index.js:30)
    at finishClassComponent (react-dom.development.js:7873)
    at updateClassComponent (react-dom.development.js:7850)
    at beginWork (react-dom.development.js:8225)
    at performUnitOfWork (react-dom.development.js:10224)
    at workLoop (react-dom.development.js:10288)
    at HTMLUnknownElement.callCallback (react-dom.development.js:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
    at invokeGuardedCallback (react-dom.development.js:438)
    at renderRoot (react-dom.development.js:10366)
    at performWorkOnRoot (react-dom.development.js:11014)
    at performWork (react-dom.development.js:10967)
    at batchedUpdates (react-dom.development.js:11086)
    at batchedUpdates (react-dom.development.js:2330)
    at dispatchEvent (react-dom.development.js:3421)

////

You html that displays the error might be not raised as you throw the error before. Try like this :

render() {
  if (this.state.counter > 5) {
    throw new Error('Ooops!');
  }
  return (
    <div>
    <div style={{cursor: 'pointer'}} onClick={this.handleClick}>Click Me: {this.state.counter}</div>
      { this.state.error &&
        <React.Fragment>
          <div>{this.state.error.toString()}</div>
          <div>{this.state.errorInfo.componentStack}</div>
        </React.Fragment>
      }
    </div>
  );
}

I think this code doesn't work, since when you throw an Error, the execution of Javascript in the function is stopped:

render() {
  if (this.state.counter > 5) {
    throw new Error('Ooops!');

    // HERE, after the Error, the exution is stopped, and all the code below is ignored.

    return(
      <React.Fragment> // this is were Error must displayed 
        <div>{this.state.error.toString()}</div>
        <div>{this.state.errorInfo.componentStack}</div>
      </React.Fragment>
    );
  }
  return <div style={{cursor: 'pointer'}} onClick={this.handleClick}>Click Me: {this.state.counter}</div>
}

What you can do is use try/catch block when throwing the Error, Or just render the error info if it exists, for example:

render() {
  if (this.state.error) {
    return(
      <React.Fragment> // this is were Error must displayed 
        <div>{this.state.error.toString()}</div>
        <div>{this.state.errorInfo.componentStack}</div>
      </React.Fragment>
    );
  }
  if (this.state.counter > 5) {
    throw new Error('Ooops!');
  }
  return <div style={{cursor: 'pointer'}} onClick={this.handleClick}>Click Me: {this.state.counter}</div>
}

This is what you can do - include executible Component component inside the error-cheker MyComponent component. It will be work:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      error: null,
      errorInfo: null
    };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ 
      error: error,
      errorInfo: errorInfo
    });
  }

  render() {
    if (this.state.errorInfo) {
      return(
        <React.Fragment>
          <div>{this.state.error && this.state.error.toString()}</div>
          <div>{this.state.errorInfo.componentStack}</div>
        </React.Fragment>
      );
    }   
    return this.props.children;
  }
}

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      counter: 0,
    };
  }

  handleClick = () => {
    this.setState({ counter: this.state.counter + 1 })
  }

  render() {
    if (this.state.counter > 5) {
      throw new Error('Ooops!');
    }
    return <div style={{cursor: 'pointer'}} onClick={this.handleClick}>Click Me: {this.state.counter}</div>
  }
}

ReactDOM.render(
  <MyComponent>
    <Component />
  </MyComponent>,
  document.getElementById('root')
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM