取消 Context.Consumer 创建的 useEffect 清理函数中的所有订阅 [英] Cancel all subscriptions in a useEffect cleanup function created by Context.Consumer

查看:55
本文介绍了取消 Context.Consumer 创建的 useEffect 清理函数中的所有订阅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次执行 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 可能仍然是未完成的"),它的 finallysetState 将在组件卸载后执行.

如果组件已安装,您可以使用简单的检查:

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屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆