取消 Context.Consumer 创建的 useEffect 清理函数中的所有订阅 [英] Cancel all subscriptions in a useEffect cleanup function created by Context.Consumer
问题描述
每次执行 onClick
时,我都会收到一条关于内存泄漏的警告消息.如何使用 useEffect
钩子从我的功能组件中的 Context.Consumer 取消订阅组件?
我没有找到取消订阅 AppContext 的方法.AppContext.unsubsribe()
不起作用.
import React, {useState, useContext} from 'react';从'react-router-dom'导入{withRouter};从 'axios' 导入 axios;从../context/AppContext"导入{AppContext};const LoginPage = (props) =>{const [name, setName] = useContext(AppContext);const [isLoading, setIsLoading] = useState(false);const onClick = () =>{setIsLoading(true);axios.post('/get-name').then(resp => {设置名称(响应);setIsLoading(false);props.history.push('/');}).catch(err => console.log(err)).finally(() => setIsLoading(false));};返回 (<div><button onClick={onClick}></button>
);};导出默认 withRouter(LoginPage);
浏览器控制台中的错误消息:
<块引用>警告:无法在未安装的
上执行 React 状态更新成分.这是一个空操作,但它表明您的内存泄漏应用.修复,取消所有订阅和异步任务在 useEffect 清理函数中.在 UserPage 中(由 Context.Consumer 创建)在路由中(由 withRouter(UserPage) 创建)在 withRouter(LoginPage) (由 Context.Consumer 创建)在路由中(由 UserRoute 创建)
你的问题是 axios 返回了一个 promise,所以当组件挂载时,它执行 axios.post(...)
点击.当它 THEN 卸载时(而 Promise 可能仍然是未完成的"),它的 finally
的 setState
将在组件卸载后执行.
如果组件已安装,您可以使用简单的检查:
import React, {useState, useContext, useEffect} from 'react';从'react-router-dom'导入{withRouter};从 'axios' 导入 axios;从../context/AppContext"导入{AppContext};const LoginPage = (props) =>{const [name, setName] = useContext(AppContext);const [isLoading, setIsLoading] = useState(false);const isMounted = useRef(null);useEffect(() => {//组件挂载时执行isMounted.current = true;返回 () =>{//卸载时执行isMounted.current = false;}}, []);const onClick = () =>{setIsLoading(true);axios.post('/get-name').then(resp => {设置名称(响应);setIsLoading(false);props.history.push('/');}).catch(err => console.log(err)).finally(() => {如果(isMounted.current){setIsLoading(false)}});};返回 (<div><button onClick={onClick}></button>
);};导出默认 withRouter(LoginPage);
Each time when onClick
executes I received a warning message about memory leak. How component can be can unsubscribed from the Context.Consumer in my functional component with useEffect
hook?
I did not find a way how to unsubscribe from the AppContext. AppContext.unsubsribe()
did not work.
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);
Error message in the browser console:
Warning: Can't perform a React state update on an unmounted
component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. in UserPage (created by Context.Consumer) in Route (created by withRouter(UserPage)) in withRouter(LoginPage) (created by Context.Consumer) in Route (created by UserRoute)
Your problem is that axios is returning a promise, so when the component is mounted, it executes axios.post(...)
on click. When it THEN unmounts (while the promise could still be "unfinished"), the setState
of its finally
will execute AFTER the component unmounted.
You can use an easy check if the component is mounted:
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);
这篇关于取消 Context.Consumer 创建的 useEffect 清理函数中的所有订阅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!