Мне удалось сделать это с помощью следующих шагов:
- Создать контекст, в котором я храню
lastVisitedLocation
, это значение редактируется, когда пользователь нажимает на ссылку. (Мы можем обновить его из любого места в приложении!) - Контекст также предоставляет функцию
registerLocation
, которая изменяет предыдущее значение.
const LocationContext = React.createContext(null);
function LocationContextProvider({ children }) {
const lastVisitedLocation = React.useRef(null);
function registerLocation(location) {
lastVisitedLocation.current = location;
}
return (
<LocationContext.Provider value={{ registerLocation, lastVisitedLocation }}>
{children}
</LocationContext.Provider>
);
}
- Обертывание
Link
из react-router-dom
и изменяйте lastVisitedLocation
всякий раз, когда мы нажимаем на ссылку.
const MySpecialLink = React.forwardRef((props, ref) => {
const { registerLocation } = React.useContext(LocationContext);
return (
<Link onClick={() => registerLocation(props.to)} ref={ref} {...props} />
);
});
- Создайте ловушку, которая проверяет, что пользователь ранее перемещался в приложении, и что мы не в разрешенном маршруте. Если мы обнаружим прямой доступ через URL, выведите ошибку (мы можем реализовать любое желаемое поведение).
const PUBLIC_ALLOWED_ROUTES = ["/home", "/"];
function useInvalidUrlAccess() {
const currentLocation = useLocation();
const { lastVisitedLocation } = React.useContext(LocationContext);
if (
lastVisitedLocation.current === null &&
!PUBLIC_ALLOWED_ROUTES.includes(currentLocation.pathname)
) {
throw new Error("Cannot come here directly, buddy");
}
}
- Оберните
Switch
в LocationContextProvider
.
<LocationContextProvider>
<MySpecialLink to="/">Home</MySpecialLink>
<br />
<MySpecialLink to="/page1">Page 1</MySpecialLink>
<br />
<MySpecialLink to="/page2">Page 2</MySpecialLink>
<br />
<Switch>
<Route exact path="/">
<HomePage />
</Route>
<Route exact path="/home">
<HomePage />
</Route>
<Route exact path="/page1">
<Page1 />
</Route>
<Route exact path="/page2">
<Page2 />
</Route>
<Route component={NotFound} />
</Switch>
</LocationContextProvider>
- Защитите свои компоненты, вызвав зацепку на верхнем уровне функции
function HomePage() {
useInvalidUrlRoutes();
return "This is the content of HOME the page";
}
function Page1() {
useInvalidUrlRoutes();
return "This is the content of the page 1";
}
function Page2() {
useInvalidUrlRoutes();
return "This is the content of the page 2";
}
function NotFound() {
return "You hit the wrong road, buddy!";
}
Наконец, вот рабочие коды и демонстрационная коробка . Я использовал throw new Error
, например, чтобы пометить маршрут как не судоходный напрямую, но в основном вы можете делать все что угодно.