![](/img/trans.png)
[英]Can't perform a React state update on an unmounted component with useEffect hook
[英]Can't perform a React state update on an unmounted component when using useEffect hook
使用useEffect
挂钩时,我似乎收到以下错误。
警告:无法对未安装的组件执行 React state 更新。 这是一个空操作,但它表明您的应用程序中存在 memory 泄漏。 要修复,请取消 useEffect 清理中的所有订阅和异步任务 function。
我相信这与我调用的异步 function 有关,以设置用户是否通过身份验证。
保护路线.tsx
export function ProtectedRoute({ ...routeProps }: ProtectedRouteProps): ReactElement | null {
const context = useContext(AppContext);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
isUserAuthenticated(context.token).then(setIsAuthenticated).catch(setIsAuthenticated);
});
if (isAuthenticated) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: "login" }} />;
}
}
const isUserAuthenticated = async (token: any): Promise<boolean> => {
try {
const response = await VerifyAuthentication(token);
console.log("VerifyAuthentication", response);
if (response.status !== 200) {
return false;
}
return true;
} catch (err) {
return false;
}
};
应用程序.tsx
class App extends Component<Props, State> {
renderRouter = () => {
return (
<Router>
<Switch>
<ProtectedRoute exact path="/" component={Dashboard} />
<Route exact path="/login" component={Login} />
</Switch>
</Router>
);
};
render(): ReactElement {
return (
<div className="App">
<AppProvider>
<Theme>
<Sidebar>{this.renderRouter()}</Sidebar>
</Theme>
</AppProvider>
</div>
);
}
}
据推测,这会将用户重定向到没有此组件的路由:
return <Redirect to={{ pathname: "login" }} />;
这意味着组件已卸载,或者通常从活动使用/内存中卸载。 这总是会发生,因为这种情况永远不会true
:
if (isAuthenticated) {
因为当组件首次呈现时,该值被显式设置为false
:
const [isAuthenticated, setIsAuthenticated] = useState(false);
所以基本上发生的事情是:
目前还不完全清楚该组件是如何适应您的整体结构的,但是您将需要更改该结构。 要么检查身份验证需要同步,要么您需要等待异步操作完成后再重定向。 后者的一个例子可以很简单:
export function ProtectedRoute({ ...routeProps }: ProtectedRouteProps): ReactElement | null {
const context = useContext(AppContext);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
isUserAuthenticated(context.token)
.then(x => {
setIsAuthenticated(x);
setIsLoading(false);
})
.catch(e => {
setIsAuthenticated(false);
setIsLoading(false);
console.log(e);
});
});
if (isLoading) {
return <div>Loading...</div>;
} else if (isAuthenticated) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: "login" }} />;
}
}
在这种情况下,isLoading 的一个单独的isLoading
值用于跟踪异步操作是否仍在进行,因此组件“等待”数据加载完毕后再决定是否重定向用户。
但总的来说,我不明白为什么身份验证检查不能同步。 更高级别的东西,例如将整个应用程序结构包装在<App/>
中的提供者组件,可以具有与上面相同的逻辑,本质上执行异步操作并将结果保存在 state 中。然后可以通过useContext
或提供 state Redux 甚至只是作为道具传递给所有子组件。
您不需要在子组件中一遍又一遍地重新检查身份验证。 这是一个应用程序级别的问题。
您可以在调用setIsAuthenticated
时使用变量来检查组件是否挂载或卸载
useEffect(() => {
let isMouted = true;
isUserAuthenticated(context.token)
.then((val) => isMouted && setIsAuthenticated(val))
.catch(setIsAuthenticated);
return () => {
isMouted = false;
};
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.