在回程中使用useErrorHandler钩子从react错误边界重置错误边界



我使用react error boundary包来显示回退UI,以防应用程序抛出任何错误。这个软件包对我来说很好。如果我使用浏览器后退按钮转到以前的页面,我需要了解如何重置应用程序错误状态,因为转到以前的网页也显示后退UI而不是原始组件。我们是否可以渲染原始组件?

在下面的代码中,用户将在Page2上抛出错误,因为我将空对象作为道具传递。在这种情况下,它将显示回退屏幕。如果我点击后退按钮,仍然会在第1页显示后退屏幕,这是我不想要的。

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>)
}

提供一个key<ErrorBoundary />。每当key发生变化时,就会重置错误边界。

在您的情况下,使用useLocation().pathname作为key意味着它将在路径更改时重置:

const location =  useLocation();
// ...
return (
<ErrorBoundary key={location.pathname}>
{/* ... */}
</ErrorBoundary>
)

作为一个单独的建议,我将在Layout组件中移动错误处理。这将允许在发生错误时保持导航,这是很好的用户体验。

这里有一个基本的例子。

导航离开时尝试重置错误状态:

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>)
}

您可以使用以下方式强制重新渲染错误边界,首先制作一个单独的功能组件来保存错误边界,并将监听器添加到历史

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>
}

当您从第2页返回到第1页时,history.localion.pathname将具有值";第2页";,由于您按后退键,该值将与window.location.pathname不匹配,因为window.location.pathname具有值"第1页";,在这个阶段,我们将导航到window.location.pathname,并在错误边界组件中使用这个值作为关键字。在编写这个答案时,我已经使用了react路由器dom V6和react v18

是一个完整的用例演示

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;

最新更新