这是我使用React Hooks的第一个项目。今天,我遇到了内存泄漏问题-我的应用程序给了我这个错误:
警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。
我研究了一些解决方案。例如,我可以使用变量来跟踪组件的状态
isMounted
。
唯一的问题是,我不确定在哪里实现此目标。例如,我的一个组件中有3个UseEffect
钩子。内存泄漏错误可归因于此特定组件。
使用效果1:
useEffect(() => {
socket.on("allLobbyClients", clients => {
if (readyList.length == clients.length) {
socket.emit("gameStarting", activeGamePin);
socket.on("gameStartingMsg", data => {
updateGameStarting(data);
});
setTimeout(() => {
navigate("/game-draw", true);
}, 5000);
}
});
}, [readyList]);
使用效果2:
useEffect(() => {
socket.on("readyClientIndexes", indexes => {
updateReadyList(indexes);
});
}, []);
使用效果3:
useEffect(() => {
socket.emit("joinRoom", activeGamePin);
socket.emit("getClientsForLobby", activeGamePin);
socket.on("allLobbyClients", data => {
//Gets the 'Client Index', which can be used to identify them in the <ol> when they specify they are ready to start the game.
let clientName = window.localStorage.getItem("clientName");
updateClientIndex(data.indexOf(clientName));
let activePlayers = data.map((client, index) => (
<li
id={index}
key={index}
className={readyList.includes(index) ? "ready" : "unready"}
>
{client}
</li>
));
updateClientList(activePlayers);
});
}, [readyList]);
我还有一个使用Axios发出POST请求的功能。
function playerIsReady() {
let gamePin = activeGamePin;
axios
.post(`${backend}/newIndex`, {
clientIndex: clientIndex,
gamePin: gamePin
})
.then(response => {
console.log(response.data);
});
setTimeout(() => {
socket.emit("playerReady", gamePin);
}, 2000);
socket.on("readyClientIndexes", indexes => {
updateReadyList(indexes);
updateReadyBtn("invisible");
});
}
我的主要问题是:内存泄漏错误可能来自何处?它源自我的useEffect挂钩之一,还是源自Axios函数?一段时间以来,我第一次对解决方案感到完全无助。
任何回复都非常感谢-非常感谢!
P.S。我怀疑该错误与Axios功能有关,因为在我的应用程序组件中发生了内存泄漏错误,该错误不利用UseEffect挂钩。因此,我被卡住了!
答案 0 :(得分:1)
我要说,您需要取消订阅socket
。通常是通过useEffect
清理功能(return () => {...}
)
实施isMounted
后,请在要设置状态异步的每个位置的前面添加条件检查:isMounted && setSomeState(..)
答案 1 :(得分:1)
在不运行代码的情况下,我可能会查看套接字正在执行的所有工作。您将它们设置为可以工作,但是在卸载组件后没有什么可以关闭它们的。考虑从可以从useEffect返回的函数中清理它们。