取消 Context.Consumer 创建的 useEffect 清理函数中的所有订阅

kus*_*sha 6 reactjs react-context react-hooks use-effect

每次onClick执行时,我都会收到一条关于内存泄漏的警告消息。如何使用钩子从我的功能组件中的Context.Consumer取消订阅组件useEffect

我没有找到如何取消订阅 AppContext 的方法。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);

Run Code Online (Sandbox Code Playgroud)

浏览器控制台中的错误消息:

警告:无法对卸载的
组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请取消 useEffect 清理函数中的所有订阅和异步任务。在UserPage(由Context.Consumer创建)在Route(由withRouter(UserPage)创建)在withRouter(LoginPage)(由Context.Consumer创建)在Route(由UserRoute创建)

Ben*_*ams 8

您的问题是 axios 返回一个承诺,因此当安装组件时,它会axios.post(...)在单击时执行。当它然后卸载时(虽然承诺仍可能“未完成”),其setStatefinally在组件卸载后执行。

您可以使用简单的方法检查组件是否已安装:

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);
Run Code Online (Sandbox Code Playgroud)


Den*_*ash 0

正如警告所述,在您的UserPage组件中,您需要执行清理useEffect以避免内存泄漏。

请参阅文档如何在效果后要求清理。

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
Run Code Online (Sandbox Code Playgroud)