javascript - Prevent React Router from accessing directly an URL without navigating
问题描述
I am trying to create a small game interface that consists of different pages (start menu, loading screen, etc).
Of course I don't want the user to be able to navigate between those pages just by changing the URL in the address bar.
Is there a way to ignore / reject user input from the address bar and just navigate the pages from within the code?
Thank you very much in advance! :)
解决方案
我可以通过以下步骤做到这一点:
- 创建一个我存储的上下文,
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
例如直接将路线标记为不可导航,但基本上你可以做任何事情。