![](/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.