javascriptreactjserror-handlingreact-error-boundary

Prevent Error Boundary from Replacing UI and Instead Show an Alert


I'm using an Error Boundary in my React application to catch errors in child components. However, whenever an error occurs, the entire component tree under the Error Boundary gets replaced by the fallback UI, resulting in a blank screen.

Instead of completely unmounting the previous component, I want to:

Keep the existing UI intact Show an alert or a popup notifying the user that there was an issue loading the next component Ensure the app remains usable despite the error Is there a way to achieve this in React, where the Error Boundary catches the error but does not unmount the existing UI? Any insights or best practices would be greatly appreciated!


Solution

  • you can do this by leveraging providers, useContext, and hooks. You can also use a library such as redux to manage that context. for a quick think. this should give you an idea on how to implement it.

    function useErrorBoundary() {
      const [error, setError] = useState(null);
    
      useEffect(() => {
        return () => setError(null);
      }, []);
    
      return [error, setError];
    }
    
    function ErrorAlert({ error, onDismiss }) {
      if (!error) return null;
      
      return (
        <div>
          An error occurred while loading content
          <button 
            onClick={onDismiss}
            style={{ marginLeft: '10px' }}
          >
            Dismiss
          </button>
        </div>
      );
    }
    
    function GentleErrorBoundary({ children }) {
      const [error, setError] = useState(null);
      
      const errorHandler = (error) => {
        console.error("Caught error:", error);
        setError(error);
      };
    
      return (
        <>
          <ErrorBoundaryContext.Provider value={errorHandler}>
            {children}
          </ErrorBoundaryContext.Provider>
          <ErrorAlert error={error} onDismiss={() => setError(null)} />
        </>
      );
    }
    
    // context
    const ErrorBoundaryContext = React.createContext(null);
    
    // Custom hook
    export function useErrorHandler() {
      return React.useContext(ErrorBoundaryContext);
    }
    

    for the unexpected errors which occurs while rendering a component, use the class component componentDidCatch(error, errorInfo) like below

    class RenderErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false, error: null };
      }
    
      static getDerivedStateFromError(error) {
        return { hasError: true, error };
      }
    
      componentDidCatch(error, errorInfo) {
        console.error("Render error caught:", error, errorInfo);
        
        if (this.props.onError) {
          this.props.onError(error);
        }
      }
    
      render() {
        if (this.state.hasError) {
      return (
        <>
          {this.props.children}
          <ErrorAlert/>
        </>
      );
    }
    
    return this.props.children;
      }
    }
    

    and then in your app.js or any component, do this:

        function App() {
          const [error, setError] = useState(null);
          
          const errorHandler = (error) => {
            console.error("Error handled:", error);
            setError(error);
          };
        
          return (
              <RenderErrorBoundary onError={errorHandler}>
                <DashBoad/>
              </RenderErrorBoundary>
          );
        }
    
     - or you can combine the functional error handler provider with the
       component error handler like this :
    
        function GentleErrorBoundary({ children }) {
          const [error, setError] = useState(null);
          
          const errorHandler = (error) => {
            console.error("Error handled:", error);
            setError(error);
          };
        
          return (
            <ErrorBoundaryContext.Provider value={errorHandler}>
              <RenderErrorBoundary onError={errorHandler}>
                {children}
              </RenderErrorBoundary>
              <ErrorAlert error={error} onDismiss={() => setError(null)} />
            </ErrorBoundaryContext.Provider>
          );
        }