每次执行onClick
时,我都会收到有关内存泄漏的警告消息。如何使用钩子从功能组件中的 Context.Consumer 取消订阅useEffect
组件?
我没有找到如何取消订阅应用程序上下文的方法。 AppContext.unsubsribe()
没有用。
import React, {useState, useContext} from 'react';
import {withRouter} from 'react-router-dom';
import axios from 'axios';
import {AppContext} from "../context/AppContext";
const LoginPage = (props) => {
const [name, setName] = useContext(AppContext);
const [isLoading, setIsLoading] = useState(false);
const onClick = () => {
setIsLoading(true);
axios.post('/get-name')
.then(resp => {
setName(resp);
setIsLoading(false);
props.history.push('/');
})
.catch(err => console.log(err))
.finally(() => setIsLoading(false));
};
return (
<div>
<button onClick={onClick}></button>
</div>
);
};
export default withRouter(LoginPage);
浏览器控制台中的错误消息:
警告:无法对卸载
的 React 状态更新 元件。这是一个无操作,但它表明您的内存泄漏 应用。若要修复,请取消所有订阅和异步任务 在 useEffect 清理函数中。 在UserPage中(由Context.Consumer创建( in Route (由 withRouter(UserPage(创建( in withRouter(LoginPage( (由 Context.Consumer 创建( 在路由中(由用户路由创建(
你的问题是 axios 返回了一个承诺,所以当组件挂载时,它会在单击时axios.post(...)
执行。当它卸载时(虽然承诺仍然可能"未完成"(,其finally
的setState
将在组件卸载后执行。
您可以使用简单的检查组件是否已挂载:
import React, {useState, useContext, useEffect} from 'react';
import {withRouter} from 'react-router-dom';
import axios from 'axios';
import {AppContext} from "../context/AppContext";
const LoginPage = (props) => {
const [name, setName] = useContext(AppContext);
const [isLoading, setIsLoading] = useState(false);
const isMounted = useRef(null);
useEffect(() => {
// executed when component mounted
isMounted.current = true;
return () => {
// executed when unmount
isMounted.current = false;
}
}, []);
const onClick = () => {
setIsLoading(true);
axios.post('/get-name')
.then(resp => {
setName(resp);
setIsLoading(false);
props.history.push('/');
})
.catch(err => console.log(err))
.finally(() => {
if (isMounted.current) {
setIsLoading(false)
}
});
};
return (
<div>
<button onClick={onClick}></button>
</div>
);
};
export default withRouter(LoginPage);
如警告所述,在UserPage
组件中,您需要对useEffect
执行清理以避免内存泄漏。
请参阅文档,了解如何要求在效果后进行清理。
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
@Bennet Dams,我可以解决我的问题,这是我按照他的例子编写的代码
const isMounted = useRef(null);
useEffect(() => {
isMounted.current = true;
fetchRequestsData();
return () => {
isMounted.current = false;
};
}, []);
async function fetchRequestsData() {
//My previous code which led to the warning
/* const { data } = await axios({
url: '../api/random/my-requests',
method: 'get',
});
setSuspendedRequests(data.suspended); */
let data;
axios
.get('../api/random/my-requests')
.then((resp) => {
data = resp.data;
})
.catch((err) => console.log(err))
.finally(() => {
if (isMounted.current) {
setSuspendedRequests(data.suspended);
}
});
}