2

下面链接的 codepen 使用react-router错误边界来捕获每个路由中的错误。

如果单击“商店”,则会按预期捕获错误,其他链接将不再起作用。这里发生了什么?为什么react-router-dom似乎停止工作?这样做的“正确”方法是什么?是<ErrorBoundary>组件有问题,还是路由组件的包装方式有问题,还是?

https://codepen.io/mpontus/pen/NyKNoL


如果 codepen 链接发生问题:

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"));
4

1 回答 1

4

简而言之,由于您ErrorBoundary对每条路线都重复使用,它永远不会被卸载(这是设计使然)。因此,它的hasError状态在每条路线上都保持不变。

您可以通过在组件内的位置更改时更新状态来缓解这种情况ErrorBoundary

  componentDidUpdate(prevProps) {
    if (prevProps.location.pathname !== this.props.location.pathname) {
      this.setState({ hasError: false });
    }
  }

由于您使用的是render道具,因此您必须手动将路由道具传递给ErrorBoundary组件:

例如:

<Route
  exact
  path="/"
  render={props => (
    <ErrorBoundary {...props}>
      <HomeScreen {...props} />
    </ErrorBoundary>
  )}
/>

工作演示(由于此代码框位于 中development,它会显示错误覆盖,因此您必须关闭错误窗口才能继续):

编辑错误边界

于 2020-02-12T23:16:49.483 回答