According to React’s own documentation, ErrorBoundaries don't catch errors for:
- Event handlers
- Asynchronous code, for example setTimeout or requestAnimationFrame callbacks
- Server side rendering
- Errors thrown in the error boundary itself (rather than its children)
These components are able to catch errors with the help of some lifecycle methods like getDerivedStateFromError and componentDidCatch. At the time of writing, a function component can't become an ErrorBoundary. There are plans however to expose the relevant lifecycle methods in hooks so that a function component can become an ErroBoundary. Until then, it depends on the project’s architecture how ErrorBoundaries are implemented.
In a JSS project that utilises function components a similar strategy can be implemented. Knowing where the most common rendering errors come from and what they are, an HOC can be prepared to wrap all renderings and catch any errors thrown. For example, a missing datasource rendering error as could be the case for a Sitecore CMS solution.
For the purposes of catching errors in a React based JSS application, we create an HOC called withFieldsCheck using a common naming convention. To catch rendering errors, they need to be identified:
- Datasource errors: For components that rely on data coming from a datasource item
- Route field errors: For components that rely on data being present on the page template itself
- Placeholder errors: For components whose children rely on datasource errors
First, create withFieldsCheck HOC. This accepts a component to enhance, as well as other options. It also imports a simple Error component to return instead of the wrapped Componentin in the case an error has been caught.
Next, set the logic for catching the three possible errors. Use the options passed to withFieldsCheck to determine what type of rendering error this component will be looking for.
- if both routeField and placeholderName are missing, the component is watching for a datasource error
- if routeField is present, the component is watching for an error due to a field missing on the page template
- if placeholderName is present, the component is watching for a datasource missing in one of its placeholder child components
It's important to note that:
- routeField is the name of a content field on the page template the component will be placed on; should that field be missing, the component has been placed on a page it may not supposed to be on
- placeholderName is the name of a placeholder field defined when setting up a component. It presents itself as an array of all children inside the component props which can then be iterated and those children checked for missing datasources
Both option fields routeField and placeholderName are of type string. The conditions are then checked before returning the component in case an error is found.
When performing the placeholderName, check an additional assertion is needed where the component's children are checked for missing datasources.
If the relevant condition check returns an error, the Error component is being rendered instead of the expected wrapped Component.
The error component checks whether you're in editing mode. If so, it returns a relevant error block so the content editing team sees that something is wrong with the rendering. Otherwise, it will return null; so that the application doesn’t crash.
The final step is to use withFieldsCheck to wrap the relevant components.
At Codehouse we're always looking at ways to improve the development process. We continually work on exciting projects often on CMS like Sitecore.