ReactJS:本地存储超出最大更新深度
ReactJS: Maximum update depth exceeded with localstorage
我有一个登录页面,用户在其中对我的服务器进行身份验证。如果用户成功通过身份验证,那么我将设置 2 个本地存储密钥 - 一个用于 token
,另一个用于 authtoken
。
用户可以在应用程序的页面之间导航,检查这些值是否存在没有任何问题。
当我注销时,注销按钮调用以下函数:
const handleLogout = () => {
logout();
history.replace("/");
};
logout()
函数简单地清除上面提到的值:
localStorage.removeItem("token");
localStorage.removeItem("refreshToken");
问题是在注销时应用程序抛出以下异常:
Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
我最初认为问题出在登录页面组件中,但我在该组件上汇总了所有内容,而且我还创建了一个空白的新页面以重定向到,但出现了相同的异常结果。
只有当我注释掉对 logout()
的调用时,路由替换才能正常工作(当然不会从本地存储中删除值)。
localstorage 是否以我没有预料到的任何方式影响状态?怎么回事?
编辑
我找到了发生循环的地方。我有一个 Protected Route 组件,如下所示:
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { isAuthenticated } from "../../services/api/auth";
function ProtectedRoute({
component: Component,
children: ChildComponent,
...rest
}) {
return (
<Route
{...rest}
render={(props) => {
if (isAuthenticated()) {
return (
(Component && <Component {...props} />) ||
ChildComponent
);
} else {
return (
<Redirect
to={{
pathname: "/",
state: { from: props.location },
}}
/>
);
}
}}
/>
);
}
export default ProtectedRoute;
当 logout()
被调用并且 history.replace("/");
发生时,它代表我的页面调用此组件(卸载?)为什么它在 "/"
页面时呈现此页面被重定向到没有使用这个组件?
我找到了我的特定问题的答案。但由于我已经从网上的一篇文章中了解了如何创建受保护的路由,这可能对可能遇到此问题但不明白为什么的其他人有用。
问题出在 ProtectedRoute
组件中。每次更改页面时都会调用它(也在空的 React 应用程序上检查)。当它在 Route
组件中调用 render
时,它会计算 isAuthenticated()
。由于身份验证数据被删除,这是错误的,因此属于 Redirect
组件,这再次导致 ProtectedRoute
成为 re-rendered - 一次又一次 - 因此 - 一个循环。
为了解决这个问题,我在组件中添加了一个列表,其中包含未受保护的路由,如果身份验证失败并且它们是活动路由,则应忽略这些路由:
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { useLocation } from "react-router-dom";
import { isAuthenticated } from "../../services/api/auth";
function ProtectedRoute({
component: Component,
children: ChildComponent,
...rest
}) {
const location = useLocation();
const unProtectedPaths = ["/"];
return (
<Route
{...rest}
render={(props) => {
if (isAuthenticated()) {
return (
(Component && <Component {...props} />) ||
ChildComponent
);
} else if (!unProtectedPaths.includes(location.pathname)) {
return (
<Redirect
to={{
pathname: "/",
state: { from: props.location },
}}
/>
);
}
}}
/>
);
}
export default ProtectedRoute;
我有一个登录页面,用户在其中对我的服务器进行身份验证。如果用户成功通过身份验证,那么我将设置 2 个本地存储密钥 - 一个用于 token
,另一个用于 authtoken
。
用户可以在应用程序的页面之间导航,检查这些值是否存在没有任何问题。
当我注销时,注销按钮调用以下函数:
const handleLogout = () => {
logout();
history.replace("/");
};
logout()
函数简单地清除上面提到的值:
localStorage.removeItem("token");
localStorage.removeItem("refreshToken");
问题是在注销时应用程序抛出以下异常:
Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
我最初认为问题出在登录页面组件中,但我在该组件上汇总了所有内容,而且我还创建了一个空白的新页面以重定向到,但出现了相同的异常结果。
只有当我注释掉对 logout()
的调用时,路由替换才能正常工作(当然不会从本地存储中删除值)。
localstorage 是否以我没有预料到的任何方式影响状态?怎么回事?
编辑
我找到了发生循环的地方。我有一个 Protected Route 组件,如下所示:
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { isAuthenticated } from "../../services/api/auth";
function ProtectedRoute({
component: Component,
children: ChildComponent,
...rest
}) {
return (
<Route
{...rest}
render={(props) => {
if (isAuthenticated()) {
return (
(Component && <Component {...props} />) ||
ChildComponent
);
} else {
return (
<Redirect
to={{
pathname: "/",
state: { from: props.location },
}}
/>
);
}
}}
/>
);
}
export default ProtectedRoute;
当 logout()
被调用并且 history.replace("/");
发生时,它代表我的页面调用此组件(卸载?)为什么它在 "/"
页面时呈现此页面被重定向到没有使用这个组件?
我找到了我的特定问题的答案。但由于我已经从网上的一篇文章中了解了如何创建受保护的路由,这可能对可能遇到此问题但不明白为什么的其他人有用。
问题出在 ProtectedRoute
组件中。每次更改页面时都会调用它(也在空的 React 应用程序上检查)。当它在 Route
组件中调用 render
时,它会计算 isAuthenticated()
。由于身份验证数据被删除,这是错误的,因此属于 Redirect
组件,这再次导致 ProtectedRoute
成为 re-rendered - 一次又一次 - 因此 - 一个循环。
为了解决这个问题,我在组件中添加了一个列表,其中包含未受保护的路由,如果身份验证失败并且它们是活动路由,则应忽略这些路由:
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { useLocation } from "react-router-dom";
import { isAuthenticated } from "../../services/api/auth";
function ProtectedRoute({
component: Component,
children: ChildComponent,
...rest
}) {
const location = useLocation();
const unProtectedPaths = ["/"];
return (
<Route
{...rest}
render={(props) => {
if (isAuthenticated()) {
return (
(Component && <Component {...props} />) ||
ChildComponent
);
} else if (!unProtectedPaths.includes(location.pathname)) {
return (
<Redirect
to={{
pathname: "/",
state: { from: props.location },
}}
/>
);
}
}}
/>
);
}
export default ProtectedRoute;