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



每次执行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(...)执行。当它卸载时(虽然承诺仍然可能"未完成"(,其finallysetState将在组件卸载后执行。

您可以使用简单的检查组件是否已挂载:

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);
        }
      });
  }

相关内容

  • 没有找到相关文章