background
When using Ant Design Pro for development, if it is a component rendering error, the whole page will be directly white screen in the production environment, resulting in a very poor user experience. Generally speaking, when there is a page error, it's OK to prompt the page error. The menu bar on the left should be able to be used normally, so the user experience will be better.
But when component rendering, it is always difficult to use try...catch to capture in the parent component. After introducing "error boundaries", React 16 can now handle this problem gracefully and achieve the effect mentioned above.
After the error boundary processing, render the renderings after the component error:
Introduction to error boundaries
According to the official website:
"The error boundary is a React component that can capture and print JavaScript errors that occur anywhere in its subcomponent tree, and it will render a standby UI instead of a crashed subcomponent tree. Error boundaries catch errors during rendering, in the constructor of the lifecycle method, and throughout the component tree. "
This sounds a bit awkward. In short, as long as you define static getDerivedStateFromError() or componentDidCatch() in a component, this component is an error boundary. When its subcomponent goes wrong, the component can sense it and then handle it according to the actual situation to prevent the whole component tree from directly crashing.
The use scenario of static getDerivedStateFromError() is to render the standby UI (that is, the application scenario of this article)
The usage scenario of componentDidCatch() is to print / record error information (for example, it is sent to BUG recording tools such as sentry, which is not used in this article)
Antd's solution to white screen
Next, we will add error boundary processing to the basic layout component src/layouts/BasicLayout.jsx of Antd Pro in combination with the specific code. When there is an error on the specific page, the user will be prompted for an error, and the left menu can still be used.
The version we use is Ant Design Pro v4. BasicLayout.jsx has been implemented with functional components, but the boundary processing cannot be done through React Hook, so we need to change back to the implementation of class components first. The code is as follows:
// src/layouts/BasicLayout.jsx // ... omit irrelevant code and change back to class components class BasicLayout extends React.Component { componentDidMount() { const { dispatch } = this.props; if (dispatch) { dispatch({ type: 'user/fetchCurrent', }); } } handleMenuCollapse = payload => { const { dispatch } = this.props; if (dispatch) { dispatch({ type: 'global/changeLayoutCollapsed', payload, }); } }; // get children authority render () { const { dispatch, children, settings, location = { pathname: '/', }, } = this.props; const props = this.props; const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || { authority: undefined, }; return (<> <ProLayout logo={logo} menuHeaderRender={(logoDom, titleDom) => ( <Link to="/"> {logoDom} {titleDom} </Link> )} onCollapse={this.handleMenuCollapse} menuItemRender={(menuItemProps, defaultDom) => { if (menuItemProps.isUrl || menuItemProps.children) { return defaultDom; } return <Link to={menuItemProps.path}>{defaultDom}</Link>; }} breadcrumbRender={(routers = []) => [ { path: '/', breadcrumbName: formatMessage({ id: 'menu.home', defaultMessage: 'Home', }), }, ...routers, ]} itemRender={(route, params, routes, paths) => { const first = routes.indexOf(route) === 0; return first ? ( <Link to={paths.join('/')}>{route.breadcrumbName}</Link> ) : ( <span>{route.breadcrumbName}</span> ); }} footerRender={footerRender} menuDataRender={menuDataRender} formatMessage={formatMessage} rightContentRender={rightProps => <RightContent {...rightProps} />} {...props} {...settings} > <Authorized authority={authorized.authority} noMatch={noMatch}> {children} </Authorized> </ProLayout> <SettingDrawer settings={settings} onSettingChange={config => dispatch({ type: 'settings/changeSetting', payload: config, }) } /> </> ); } };
Then, based on this code, add the processing code of error boundary:
class BasicLayout extends React.Component { constructor(props) { super(props); // Default no errors this.state = { hasError: false }; } // Add error boundary code. When an error occurs, the hasError in state will become true static getDerivedStateFromError() { return { hasError: true }; } render () { const { hasError } = this.state; return (<> {/* Omit irrelevant code */} <ProLayout > <Authorized authority={authorized.authority} noMatch={noMatch}> {/* When an error occurs, render the error prompt component */} {hasError ? <Result status="error" title="Program error, please feedback to service provider" /> : children} </Authorized> </ProLayout> <>) } }
Complete code file click here to download
https://raw.githubusercontent.com/pheye/shopify-admin/master/src/layouts/BasicLayout.jsx
test
We take the example project provided by the government as an example to make the analysis page go wrong directly. In render(), add a sentence "throw new error";, and you can see the effect of rendering error.
Epilogue
Note: error boundaries can only capture errors of their subcomponents, not their own.
Therefore, the error boundary in src/layouts/BasicLayout.js can ensure that the menu bar on the left will work normally when the page is in error. However, if the side bar or the head of BasicLayout.js is in error, the screen will also be white. Other files of src/layouts do not have error boundaries, and the error screen will also be white. To solve this problem, you can make a layer of assembly for the root component, add boundary processing, and give users more friendly tips.
However, the processing of the root component cannot replace the addition of boundary processing to BasicLayout.js alone, because we hope that the menu bar can be used normally after an error occurs.
The best error boundary handling strategy is that the root component provides a unified error handling, and different typesetting component prompts provide more friendly error handling according to the typesetting.