This guide covers how to handle errors in your React Storefront application.
Whenever an error is thrown on the client or on the server, src/errorReporter.js
is called. Here you can pass the error along to the error logging service of your choice:
// src/errorReporter.js
/**
* Called whenever an error is throw, including:
*
* React rendering on the client and server
* Route handlers on the server client and server
* All unhandled rejections on the client
* All uncaught errors on the client
*
* @param {Object} event
* @param {Error} event.error The error that was thrown.
* @param {AppModel} options.app The current app state. This may be null in some cases if the error prevented a state from being computed
* @param {History} options.history The JS history object. You can use this to get the current location.
*/
export default function errorReporter({ error, app, history }) {
// TODO: report errors to the error logging service of your choice here.
console.error(error)
}
The react-storefront-extensions
commercial package makes it easy to report errors to Airbrake:
// src/errorReporter.js
import AirbrakeClient from 'airbrake-js'
import { createAirbrakeReporter } from 'react-storefront-extensions/error-reporters'
export default createAirbrakeReporter(
new AirbrakeClient({
projectId: XXXXXX,
projectKey: 'XXXXXXXXXXXXXXXXXXXXXXX'
})
)
React Storefront's Router
provides an error
handler that is called whenever an error is thrown from a route handler on either the client or the server:
new Router().error((error, params, request, response) => {
response.status(500)
return {
page: 'Error',
error: e.message,
loading: false,
stack: e.stack
}
})
Like all other route handlers, the error
handler returns data to be applied to the app's state tree. In the example above, we return a state object that will cause the app to hide the loading mask (if one is present) and display the error page. This matches the default functionality that is provided if you do not provide an error handler.
React Storefront automatically catches all errors that occur during React rendering and updates the following attributes on the app state:
page
is set to "Error"error
is set to the error's messagestack
is set to the error's stackYou can configure a catch-all error page for your app in the Pages
component in src/App.js
.
<Pages
loadMasks={{
Category: CategorySkeleton,
Subcategory: SubcategorySkeleton,
Product: ProductSkeleton
}}
components={universal => ({
Home: universal(import('./home/Home')),
Category: universal(import('./category/Category')),
Subcategory: universal(import('./subcategory/Subcategory')),
Product: universal(import('./product/Product')),
Cart: universal(import('./cart/Cart')),
Checkout: universal(import('./checkout/Checkout')),
// Here we configure the page to displayed when an error occurs
Error: universal(import('./ErrorPage')),
Offline
})}
/>
When you create a new app with create-react-storefront
, it comes with a default error page that displays the full stack trace in development, and a simple error message in production:
import React, { Component } from 'react'
import Typography from '@material-ui/core/Typography'
import Container from 'react-storefront/Container'
import Row from 'react-storefront/Row'
import Redbox from 'react-storefront/Redbox'
export default class ErrorPage extends Component {
render() {
if (process.env.MOOV_ENV === 'production') {
// In production we return a generic, user-friendlt error page that hides the underlying message and stacktrack
return (
<Container>
<Row>
<Typography variant="h6">Error</Typography>
</Row>
<Row>
<Typography>
An unknown error occurred while attempting to process your request. Please try again
later.
</Typography>
</Row>
</Container>
)
} else {
// In development, we display react-storefront/Redbox to help with debugging
return <Redbox />
}
}
}