当错误边界在路由中捕获错误时,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>