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 });
}
}
Поскольку вы используете render
prop, вам придется вручную передать свойства маршрута в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>