4

I have the following code in index.tsx:

window.onerror = function(msg, url, line, col, error) {
   debugger;
   // Note that col & error are new to the HTML 5 spec and may not be 
   // supported in every browser.  It worked for me in Chrome.
   var extra = !col ? '' : '\ncolumn: ' + col;
   extra += !error ? '' : '\nerror: ' + error;

   // You can view the information in an alert to see things working like this:
   alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);

   // TODO: Report this error via ajax so you can keep track
   //       of what pages have JS issues

   var suppressErrorAlert = true;
   // If you return true, then error alerts (like in older versions of 
   // Internet Explorer) will be suppressed.
   return suppressErrorAlert;
};

Source:

https://stackoverflow.com/a/10556743/3850405

If I throw an error like this in another component I will catch it as expected:

componentDidMount() {
    throw new Error();
}

enter image description here

If thrown like this:

async componentDidMount() {
    throw new Error();
}

The error is not catched and an Unhandled Rejection (Error): is shown.

enter image description here

I then tried to create a React global error boundary.

import React, { ErrorInfo } from 'react';

interface IProps {

}

interface IState {
    hasError: boolean
}

class ErrorBoundary extends React.PureComponent<IProps, IState> {
    constructor(props: IProps) {
        super(props);
        this.state = { hasError: false };
    }

    componentDidCatch(error: Error, info: ErrorInfo) {
        // Display fallback UI
        debugger;
        console.warn(error);
        console.warn(info);

        this.setState({ hasError: true });
        // You can also log the error to an error reporting service
        //logErrorToMyService(error, info);
    }

    render() {
        if (this.state.hasError) {
            // You can render any custom fallback UI
            return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
    }
}

export default ErrorBoundary

index.tsx:

<React.StrictMode>
    <Provider store={store}>
        <ConnectedIntlProvider>
            <Router>
                <ErrorBoundary>
                    <App />
                </ErrorBoundary>
            </Router>
        </ConnectedIntlProvider>
    </Provider>
</React.StrictMode>,

Sources:

https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html

https://stackoverflow.com/a/51764435/3850405

The effect was however the same, async componentDidMount was not caught but otherwise it worked as expected.

enter image description here

I have found this thread that mentions the problem but no real solution.

https://stackoverflow.com/a/56800470/3850405

How can I create a global error handler in React that really catches everything?

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • 3
    [Have you looked into Promise rejection events?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Promise_rejection_events) – Pointy Oct 12 '20 at 13:09
  • @Pointy Yes but I would prefer a React way like error boundary but for Unhandled Rejections – Ogglas Oct 12 '20 at 13:12
  • Well, `async` and the Promise implementation are native JavaScript, and React can't do much to control that. – Pointy Oct 12 '20 at 13:12
  • @Pointy True but errors are native as well, React does handle them as seen above. – Ogglas Oct 12 '20 at 13:14
  • Yes, but errors in a Promise chain are dealt with by the Promise mechanism, because there are robust behavior guarantees about how that works — completely independent of React. Those "unhandled rejection" events are posted internally directly to the global context (`window` or a Worker global scope). – Pointy Oct 12 '20 at 13:21
  • @Pointy Thanks for the explanation, will have to solve it in vanilla JS then. – Ogglas Oct 12 '20 at 13:57

1 Answers1

3

After discussion with @Pointy I decided to solve it like this:

window.onerror = (msg, url, line, col, error) => {
    // Note that col & error are new to the HTML 5 spec and may not be 
    // supported in every browser.  It worked for me in Chrome.
    var extra = !col ? '' : '\ncolumn: ' + col;
    extra += !error ? '' : '\nerror: ' + error;

    // You can view the information in an alert to see things working like this:
    console.error("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);

    // TODO: Report this error via ajax so you can keep track
    //       of what pages have JS issues

    var suppressErrorAlert = true;
    // If you return true, then error alerts (like in older versions of 
    // Internet Explorer) will be suppressed.
    return suppressErrorAlert;
};

window.onunhandledrejection = (e: PromiseRejectionEvent) => {
    console.error(e);
    throw new Error(e.reason.stack);
}

Source:

https://stackoverflow.com/a/58267314/3850405

Ogglas
  • 62,132
  • 37
  • 328
  • 418