'reset error boundary on back journey using useErrorHandler hook from react-error-boundary
I am using react-error-boundary package to show the fall back UI in case application throws any errors. The package works fine for me. I need to understand how to reset application error state if I go to previous pages using browser back button as going to previous pages also shows the fall back UI instead of original component. Is there anyway we can render the original component?
In below code user will be thrown error on Page2 since I am passing empty object as props. It will show fallback screen in that case. If I click on back button still fallback screen will be shown on Page1 as well which I don't want.
App.js
const errorHandler = (error) =>{
console.log(error)
}
<BrowserRouter basename={'/bookingtool/obt/'}>
<ErrorBoundary FallbackComponent={Fallback} onError={errorHandler}>
<Routes>
<Route path="/page1" element={<Page1 PageName="Page1" />} />
<Route path="/page2" element={<Page2 PageName={{}} /> } />
</Routes>
<ErrorBoundary />
</BrowserRouter>
Page1.js
import { useErrorHandler } from 'react-error-boundary';
const Page1 = ({PageName}) =>{
return(<p>{PageName}</p>)
}
Page2.js
import { useErrorHandler } from 'react-error-boundary';
const Page2 = ({PageName}) =>{
return(<p>{PageName}</p>)
}
Fallback.js
import React from "react";
const Fallback= (props) => {
return(<h1>Something went wrong</h1>)
}
Solution 1:[1]
Provide a key to <ErrorBoundary />. Whenever the key changes, the error boundary is reset.
In your case, using useLcation().pathname as key means it will reset whenever the path changes:
const location = useLocation();
const [path, setPath] = useState(location.pathname);
useLayoutEffect(
() => setPath(location.pathname),
[location.pathname]
);
// ...
return (
<ErrorBoundary key={path}>
{/* ... */}
</ErrorBoundary>
)
As a separate suggestion, I'd move the error handling inside a Layout component. This would allow keeping the navigation when an error happens, which is good UX.
A basic example here.
Solution 2:[2]
Try to reset the error state when you navigate away:
const Fallback= ({ error, resetErrorBoundary} ) => {
const location = useLocation();
const errorLocation = useRef(location.pathname);
useEffect(() => {
if (location.pathname !== errorLocation.current) {
resetErrorBoundary();
}
},[location.pathname])
return(<h1>Something went wrong</h1>)
}
Solution 3:[3]
you can force re-render of error boundary using following way, first make a separate functional component that holds the error boundary and add listener to history
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
//a fallback component
const ErrorFallback = () => {
return <>
<h1>Something went wrong.</h1>
<button onClick={() => {
history.back();
}}>go back </button>
</>
}
function RoutesContainer() {
const [update, setUpdate] = useState(false);
let navigate = useNavigate();
const historyChange = () => {
if (window.location.pathname !== history.location.pathname) {
navigate(window.location.pathname, { replace: true });
}
};
useEffect(() => {
history.listen(historyChange)
}, [historyChange])
return <ErrorBoundary key={window.location.pathname} FallbackComponent={ErrorFallback}>
<Routes>
<Route path="/page1" element={<Page1 PageName="Page1" />} />
<Route path="/page2" element={<Page2 PageName={{}} />} />
</Routes>
</ErrorBoundary>
}
at the time when you go back to the page1 from page2,history.location.pathname will have value "page2",since you press back,this value will not match to window.location.pathname,as window.location.pathname has value "page1",at this stage we will navigate to window.location.pathname,and use this value as key in our error boundary component.at the time of writing this answer i have used react-router-dom V6,and react v18
a complete demo of use case is here
import React, { useEffect, useState } from 'react';
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom';
import { createBrowserHistory } from "history";
import { useNavigate } from "react-router-dom";
import { ErrorBoundary } from 'react-error-boundary'
const history = createBrowserHistory();
const ErrorFallback = () => {
return <>
<h1>Something went wrong.</h1>
<button onClick={() => {
history.back();
}}>go back </button>
</>
}
const Page1 = ({ PageName }) => {
return (<p>{PageName}
<Link to={'/page2'} >page 2</Link>
</p>)
}
const Page2 = ({ PageName }) => {
return (<p>{PageName}</p>)
}
function RoutesContainer() {
const [update, setUpdate] = useState(false);
let navigate = useNavigate();
const historyChange = () => {
if (window.location.pathname !== history.location.pathname) {
navigate(window.location.pathname, { replace: true });
}
};
useEffect(() => {
history.listen(historyChange)
}, [historyChange])
return <ErrorBoundary key={window.location.pathname} FallbackComponent={ErrorFallback}>
<Routes>
<Route path="/page1" element={<Page1 PageName="Page1" />} />
<Route path="/page2" element={<Page2 PageName={{}} />} />
</Routes>
</ErrorBoundary>
}
function App() {
return (
<BrowserRouter><RoutesContainer /></BrowserRouter>
);
}
export default App;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Istvan Tabanyi |
| Solution 3 |
