attempting to access properties on null or undefined values causes internal server errors, breaks entire site
-
defensive programming
- idioms like
if (!object) return null,object && object.value1 && object.value1.value2, and lodash'sget(object, 'value1.value2') - consideration: no errors are thrown, need to rely on humans in some cases to notice something wrong with or missing on the front-end
- idioms like
-
falcon and content editing
- ensure data validity and correctness in falcon
- consideration: this is good approach, but it's a longer term project and guranteeing we catch all cases is difficult, to say the least
- the
safeRenderhigher-order component uses the new ReactcomponentDidCatchlifecycle method to gracefully handle errors and to prevent the entire site from crashing - it still throws the actual error, so we can still detect errors in development and in sentry
considerations:
- what granularity should it be utilized? so far, it's seemed most appropriate for smaller components as opposed to at the route or page level
- right now safeRender won't render anything if there's an error, it might be better to render a "something's wrong here" component in all environments except production so we can catch issues even quicker
import React from 'react';
const safeRender = WrappedComponent =>
class SafeRender extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
};
}
componentDidCatch(error, info) {
this.setState({ hasError: true });
console.group(`safeRender: exception caught in component ${WrappedComponent.name}`);
console.warn(
'The following error and component stack were caught by safeRender, this likely means there is missing or malformed data:',
);
console.error(error, info.componentStack);
console.groupEnd();
}
render() {
return this.state.hasError ? null : <WrappedComponent {...this.props} />;
}
};
export default safeRender;using safeRender:
export default createFragmentContainer(safeRender(FeaturedMember), {
node: graphql`
fragment FeaturedMember_node on ArticleFP2 {
...NodeLink_node
newLeadArt {
leadImage {
...ImageWiper_leadImage
}
}
originalLeadArt {
leadImage {
...MultiSourceImage_image
... on Image {
large0_5x: imageSourceUrl(width: 600, height: 600, pixelRatio: 0.5) {
...MultiSourceImage_sources
}
}
}
}
}
`,
});