React-router перестает работать, когда граница ошибок улавливает ошибку в маршруте

Код, ссылка на который приведена ниже, использует react-router и граница ошибок для обнаружения ошибок в каждом маршруте.

Если вы нажмете "Магазин", ошибка будет обнаружена, как и ожидалось, но другие ссылки больше не работают. Что тут происходит? Почемуreact-router-domвроде перестать работать? Как это сделать "правильно"? Это проблема с<ErrorBoundary> компонент, или способ упаковки компонентов маршрута, или?

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


Если что-то случится со ссылкой на кодовый код:

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

2 ответа

Решение

Короче говоря, поскольку вы повторно используете ErrorBoundaryдля каждого маршрута он никогда не отключается (это сделано намеренно). Таким образом, егоhasError состояние сохраняется на каждом маршруте.

Вы можете смягчить это, обновив состояние при изменении местоположения в пределах ErrorBoundary составная часть:

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

Поскольку вы используете renderprop, вам придется вручную передать свойства маршрута вErrorBoundary составная часть:

Например:

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

Рабочая демонстрация (поскольку этот кодовый ящик находится вdevelopment, он покажет наложение с ошибкой, поэтому вам придется закрыть окно с ошибкой, чтобы продолжить):

Изменить границу ошибки

для записи, я думаю, что если вы не хотите, чтобы проблема с состоянием ошибки оставалась после изменения маршрута и определения границы ошибки на каждом маршруте в rr 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>
Другие вопросы по тегам