2

In my app if any errors occur inside components I need to redirect to a top-level error page. Suppose I'm using React-Router and have the following route defined,

<Switch>
   ..
   <Route path="/error">
      <Error />
   </Route>

Suppose in some down-level component something fails. I get an error object with .message and .stack. I need my Error component to display the error details after a Router <Redirect />.

const [error, setError] = useState({});

const someComponentFetch = async () => {
    const url = '/myapp/data';
    try {
         //...
    }
    catch (error) { 
        setError(error);
    }
}  

if (error.message) {
    return <Redirect to="/error" />
}

return (..);

Error component expects a props object:

export default function Error(props) {
    return (
        <div>
            Error Occurred: 
            <div>
                Message: {props.error.message} <br/>
                Stack: {props.error.stack}
            </div>
        </div>
    );
}

Error: TypeError: props.error is undefined . So <Redirect> doesn't pass my properties. What's the best way to have a top-level Error page with error details? If I were to check error ? .. in every component it wouldn't be a top-level page, it would be a message inside each component.

1

2 Answers 2

3

You can define your own represtation like this,

import React from 'react'

class ErrorBoundary extends React.Component {
    constructor(props) {
      super(props);
      this.state = { hasError: false, error: '', info: '', stack: '' }
    }
  
    static getDerivedStateFromError(error) {
      // Update state so the next render will show the fallback UI.
      return { hasError: true };
    }
  
    componentDidCatch(error, errorInfo) {
      // You can also log the error to an error reporting service
      // logErrorToMyService(error, errorInfo)
      this.setState({error, info: errorInfo, stack: error.stack})
    }
  
    render() {
      if (this.state.hasError) {
        // You can render any custom fallback UI
        return <h4>Something went wrong!</h4>;
      }
  
      return this.props.children; 
    }
}

export default ErrorBoundary

You can render error, info, and stack as per your need. You can use 'react-json-view' package to render the error and stack nicely.

And wrap your App with your error boundary,

<ErrorBoundary>
   <App />
</ErrorBoundary>
Sign up to request clarification or add additional context in comments.

Comments

0

We just ended up redirecting to /error?... with a custom parameter string that tells the Error component what to display. When setting the Error object, we set all the data items we want to capture.

const [errorObj, setErrorObj] = useState({});

From Ajax, where errors can possibly get set:

catch (error) { 
    // We capture 2 data items for an error in a custom object: message and location.
    // Any other data items can also be in this custom object.
    setErrorObj({message: error.message, location: 'approvals.js: fetchTeleworkInfo'});
}

On render:

    errorObj.message
    ?
        <Redirect to={generatePath('./error?msg=:errorMessage', 
                                   {errorMessage: formatError(errorObj)})} />
    :
        {/* Continue with normal render */}
        <div>...</div>

The utility function formatError will produce some encoded string from the Error Object:

// Format error object into a string (expects errorObj.message and errorObj.location fields)
// Error string is encoded (and decoded in the Error component) to support URL passing
export function formatError(errorObj) {
    let result = '';
    if (errorObj) {
        if (errorObj.message) {
            result += errorObj.message;
        } 
        if (errorObj.location) {
            result += ' (' + errorObj.location + ')';
        }
    }
    return encodeURIComponent(result);
}

The Error component can work either from a prop or a URL. This is an example of how it reads the URL param:

export default function Error(props) {

    // Obtain URL Params (optional)
    // ----------------------------
    const queryStr = new URLSearchParams(useLocation().search); 

    let message = null;
    if (props.msg) {    // Error string from property
       message = props.msg;
    } else if (queryStr.get("msg")) {   // Error string from React-Router URL param
       message = queryStr.get("msg");
    }
    // Decode string since it always comes in encoded
    if (message) {
       message = decodeURIComponent(message);
    }

Then the Error component can render/format errors and check the message string as it wants, e.g.

    {message &&     
        <div>..</div>
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.