如何避免 React Router 私有路由中的无限循环?
Posted
技术标签:
【中文标题】如何避免 React Router 私有路由中的无限循环?【英文标题】:How can I avoid infinite loops in my React Router private routes? 【发布时间】:2021-07-25 10:08:21 【问题描述】:在我的 App.js 中,我有一些通过 <PrivateRoute>
保护的经过身份验证的页面,如下所示:
<PrivateRoute path="/dashboard">
<Dashboard />
</PrivateRoute>
我像这样实现<PrivateRoute>
:
function PrivateRoute( children, ...rest )
return (
<Route ...rest render=() => <CheckRedirect children=children /> />
);
问题是,<CheckRedirect>
函数调用了我服务器上的一个端点,该端点动态地告诉你重定向到哪里。
函数如下:
export const CheckRedirect = ( children ) =>
const [isChecking, setIsChecking] = React.useState(true);
const [target, setTarget] = React.useState(null);
const url = "https://example.com/get-redirect"
useEffect(() =>
async function getPage()
axios.get(url)
.then(function (response)
setTarget(response.data.message)
).finally(() => setIsChecking(false))
getPage();
, []);
if (isChecking)
return "... Checking";
return target ? (
<Redirect to=target />
) : (
<Redirect to='/404' />
);
;
如果您没有登录,它会在message
字段中发回“/login”。如果您已登录,它将发送“/dashboard”。
如果它发回“/dashboard”,那么 React Router会产生一个无限循环! 它会再次尝试相同的<PrivateRoute>
,它会再次调用端点,它会再次返回“ /dashboard”等等……
如果这已经是重定向的结果,我有没有办法告诉我的<PrivateRoute>
不执行<CheckRedirect>
函数?
【问题讨论】:
我很确定您应该能够将当前路由名称从PrivateRoute
发送到您的CheckRedirect
函数,并且只有在您的getPage
fetch 中执行setTarget
,如果它返回不同的路线。
@benomatis 你能给我举个例子吗?如果我不做setTarget
,那么它将在底部返回switch 语句的<Redirect to='/404' />
部分。我需要 PrivateRoute 以某种方式永远不会调用 CheckRedirect
函数
【参考方案1】:
我自己还没有测试过,但是您是否尝试过将path
作为道具传递给CheckRedirect
,并且只在getPage
中提取setTarget
,如果它返回不同的路线?
function PrivateRoute( children, path, ...rest )
return (
<Route ...rest render=() => <CheckRedirect children=children path=path /> />
);
export const CheckRedirect = ( children, path ) =>
const [isChecking, setIsChecking] = React.useState(true);
const [target, setTarget] = React.useState(null);
const url = "https://example.com/get-redirect"
useEffect(() =>
async function getPage()
axios.get(url)
.then(function (response)
const newPath = response.data.message
if (path !== newPath)
setTarget(newPath)
).finally(() => setIsChecking(false))
getPage();
, []);
if (isChecking)
return "... Checking";
return target ? (
<Redirect to=target />
) : (
<Redirect to='/404' />
);
;
为避免CheckRedirect
在一切正常的情况下进行任何重定向(即,这是对该路由的有效请求),请确保CheckRedirect
在这种情况下实际上返回null
。如果您可以控制服务器响应,我会为不存在的路由(即重定向到 404)返回一个不同的值(不是null
,而是-1
),并在何时保留null
你真的只想返回null
。
【讨论】:
如果我不调用setTarget
,该函数将返回底部的<Redirect to='/404' />
行。我认为我们需要PrivateRoute
从不调用 CheckRedirect
函数
你应该可以只返回 null,这应该可以,我想......我会更新我的答案
或者children
?
您是否可以控制从服务器返回的响应?如果你这样做了,那么我只需在那里更改 return 语句并确保它返回特定于触发器 404 的内容,即。 -1
而不是null
,并保持null
只返回null
,以防你不想要重定向......将返回null
(只是简单的null
,没有<Redirect>
组件)在CheckRedirect
工作,你能试试吗?
返回null
只是将我重定向回主页/
,而不是呈现仪表板组件。我不确定为什么。我不认为服务器响应是这里的问题,而是我们在客户端的处理方式。【参考方案2】:
在CheckRedirect
组件中,您甚至不使用 children 道具。它呈现一个字符串,然后重定向到一个页面。它永远循环是正常的。将 path
作为 props 传递给 CheckRedirect
组件,如果它与服务器响应相同,则渲染子组件。
添加路径属性并传递它:
export const CheckRedirect = ( children, path ) =>
在重定向之前添加条件:
if (target === path)
return children
【讨论】:
不幸的是,这并没有解决我有 不同 PrivateRoute 的情况,例如:<PrivateRoute path="/account"> <OtherComponent> </PrivateRoute>
如果用户去/account
,然后CheckRedirect函数返回/dashboard
,那么无限循环再次发生(因为在这种情况下path
不等于target
)【参考方案3】:
只需将您的 PrivateRoute Logic 更改为类似的内容
const PrivateRoute = ( component: Component, ...rest ) =>
return (
<Route
...rest
render = props =>
user.isOnline ? ( <Component ...props /> ) :
(
<Redirect
to=
pathname: "/login",
state: from: props.location
/>
)
/>
)
然后
<PrivateRoute exact path="/dashboard" component=Dashboard />
【讨论】:
以上是关于如何避免 React Router 私有路由中的无限循环?的主要内容,如果未能解决你的问题,请参考以下文章
(通用 React + redux + react-router)如何避免在初始浏览器加载时重新获取路由数据?
如何使用 Apollo 和 React Router 避免嵌套路由/查询组件的请求瀑布?
从cookie异步加载身份验证令牌时,React react-router-dom私有路由不起作用