当错误边界在路由中捕获错误时,React-router 停止工作
React-router stops working when error boundary catches an error in route
codepen link编辑到下面,使用 react-router
和错误边界来捕获每个路由中的错误。
如果您单击 "Shop",将按预期捕获错误,但 其他 link 将不再起作用。这里发生了什么?为什么 react-router-dom
似乎停止工作? "correct" 的方法是什么?是 <ErrorBoundary>
组件的问题,还是路由组件的包装方式问题,还是?
https://codepen.io/mpontus/pen/NyKNoL
万一codepen出问题link:
const { BrowserRouter, Switch, Route, NavLink } = ReactRouterDOM;
class ErrorBoundary extends React.Component {
state = { hasError: false };
componentDidCatch(error, info) {
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <h1>An error has occured.</h1>;
}
return this.props.children;
}
}
const HomeScreen = () => <h3>Home</h3>;
const ProfileScreen = () => <h3>Profile Screen</h3>;
const ShopScreen = () => {
throw new Error("Error during render");
};
const App = () => (
<BrowserRouter>
<div className="container">
<nav className="nav nav-pills">
<NavLink exact className="nav-link" activeClassName="active" to="/">
Home
</NavLink>
<NavLink className="nav-link" activeClassName="active" to="/profile">
Profile
</NavLink>
<NavLink className="nav-link" activeClassName="active" to="/shop">
Shop
</NavLink>
</nav>
<Switch>
<Route
exact
path="/"
render={() => (
<ErrorBoundary>
<HomeScreen />
</ErrorBoundary>
)}
/>
<Route
path="/profile"
render={() => (
<ErrorBoundary>
<ProfileScreen />
</ErrorBoundary>
)}
/>
<Route
path="/shop"
render={() => (
<ErrorBoundary>
<ShopScreen />
</ErrorBoundary>
)}
/>
</Switch>
</div>
</BrowserRouter>
);
ReactDOM.render(<App />, document.getElementById("root"));
简而言之,由于您为每条路线重复使用 ErrorBoundary
,因此它永远不会卸载(这是设计使然)。因此,它的 hasError
状态在每条路线上持续存在。
您可以通过在 ErrorBoundary
组件中的位置发生变化时更新状态来缓解这种情况:
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) {
this.setState({ hasError: false });
}
}
由于您使用的是 render
属性,因此您必须手动将 route props 传递给 ErrorBoundary
组件:
例如:
<Route
exact
path="/"
render={props => (
<ErrorBoundary {...props}>
<HomeScreen {...props} />
</ErrorBoundary>
)}
/>
工作演示(因为这个codesandbox在development
,它会显示一个错误覆盖,所以你必须关闭错误window 继续):
郑重声明,我想如果你不想在更改路由后仍然存在错误状态问题并在 r.r v6 中的每条路由上定义错误边界,你可以像下面这样解决它:
a:定义变量以保存上一个位置:
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
this.prevPath = null;
}
static getDerivedStateFromError(error) {
return { error: true, errorInfo: error };
}
b: 在组件上设置当前位置挂载
componentDidMount() {
this.prevPath = window.location.pathname;
}
c: 最后做了更新应该是这样的:
componentDidUpdate() {
if (window.location.pathname !== this.prevPath)
this.setState({ error: null, errorInfo: null });
this.prevPath = window.location.pathname;
}
d:像这样包装出口:
<ErrorBoundry>
<Outlet />
</ErrorBoundry>
codepen link编辑到下面,使用 react-router
和错误边界来捕获每个路由中的错误。
如果您单击 "Shop",将按预期捕获错误,但 其他 link 将不再起作用。这里发生了什么?为什么 react-router-dom
似乎停止工作? "correct" 的方法是什么?是 <ErrorBoundary>
组件的问题,还是路由组件的包装方式问题,还是?
https://codepen.io/mpontus/pen/NyKNoL
万一codepen出问题link:
const { BrowserRouter, Switch, Route, NavLink } = ReactRouterDOM;
class ErrorBoundary extends React.Component {
state = { hasError: false };
componentDidCatch(error, info) {
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <h1>An error has occured.</h1>;
}
return this.props.children;
}
}
const HomeScreen = () => <h3>Home</h3>;
const ProfileScreen = () => <h3>Profile Screen</h3>;
const ShopScreen = () => {
throw new Error("Error during render");
};
const App = () => (
<BrowserRouter>
<div className="container">
<nav className="nav nav-pills">
<NavLink exact className="nav-link" activeClassName="active" to="/">
Home
</NavLink>
<NavLink className="nav-link" activeClassName="active" to="/profile">
Profile
</NavLink>
<NavLink className="nav-link" activeClassName="active" to="/shop">
Shop
</NavLink>
</nav>
<Switch>
<Route
exact
path="/"
render={() => (
<ErrorBoundary>
<HomeScreen />
</ErrorBoundary>
)}
/>
<Route
path="/profile"
render={() => (
<ErrorBoundary>
<ProfileScreen />
</ErrorBoundary>
)}
/>
<Route
path="/shop"
render={() => (
<ErrorBoundary>
<ShopScreen />
</ErrorBoundary>
)}
/>
</Switch>
</div>
</BrowserRouter>
);
ReactDOM.render(<App />, document.getElementById("root"));
简而言之,由于您为每条路线重复使用 ErrorBoundary
,因此它永远不会卸载(这是设计使然)。因此,它的 hasError
状态在每条路线上持续存在。
您可以通过在 ErrorBoundary
组件中的位置发生变化时更新状态来缓解这种情况:
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) {
this.setState({ hasError: false });
}
}
由于您使用的是 render
属性,因此您必须手动将 route props 传递给 ErrorBoundary
组件:
例如:
<Route
exact
path="/"
render={props => (
<ErrorBoundary {...props}>
<HomeScreen {...props} />
</ErrorBoundary>
)}
/>
工作演示(因为这个codesandbox在development
,它会显示一个错误覆盖,所以你必须关闭错误window 继续):
郑重声明,我想如果你不想在更改路由后仍然存在错误状态问题并在 r.r v6 中的每条路由上定义错误边界,你可以像下面这样解决它:
a:定义变量以保存上一个位置:
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
this.prevPath = null;
}
static getDerivedStateFromError(error) {
return { error: true, errorInfo: error };
}
b: 在组件上设置当前位置挂载
componentDidMount() {
this.prevPath = window.location.pathname;
}
c: 最后做了更新应该是这样的:
componentDidUpdate() {
if (window.location.pathname !== this.prevPath)
this.setState({ error: null, errorInfo: null });
this.prevPath = window.location.pathname;
}
d:像这样包装出口:
<ErrorBoundry>
<Outlet />
</ErrorBoundry>