【问题标题】:React memory leak error (Can't perform a React state update on an unmounted component)React 内存泄漏错误(Can't perform a React state update on an unmounted component)
【发布时间】:2022-01-11 16:11:43
【问题描述】:

我主要是在移动组件时遇到此错误。谁能帮我吗。我已经尝试了 abortController 和 mount state 解决方案,但它们都不起作用

警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。 在FeedVideo

import { FC, useEffect, useState } from 'react';
import ReactPlayer from 'react-player';
import { FeedVideoProps } from '../../utils/types/interfaces';
import { getDecodedMedia } from '../../utils/helpers/getS3URL';

const FeedVideo: FC<FeedVideoProps> = ({ s3Key }: FeedVideoProps) => {
  const [videoLink, setVideoLink] = useState<string>('');
  const [isPlaying, setIsPlaying] = useState<boolean>(true);

  const getURL = async (key: string) => {
    const link: string | object = await getDecodedMedia(key);
    setVideoLink(link as string);
  };

  useEffect(() => {
    const abortController = new AbortController();
    getURL(s3Key).then(() => abortController.abort());
    return () => {
      abortController.abort();
    };
  }, [s3Key]);

  return (
    <ReactPlayer
      stopOnUnmount={true}
      className={'react-player'}
      controls={true}
      url={videoLink}
      playing={isPlaying}
    />
  );
};

export default FeedVideo;

这是我正在使用的组件的代码。

【问题讨论】:

  • 我一直在寻找解决方案,但我认为没有。卸载组件后,您根本无法阻止异步调用。您可以取消它并隐藏警告,但内存泄漏仍然存在。你最好的选择是将异步调用转移到父组件并重写你的逻辑,这样你的 FeedVideo 就不会这么快被卸载。

标签: reactjs typescript react-hooks aws-amplify react-player


【解决方案1】:

我不会太担心它,因为它只是在卸载后发生某些状态更新时 React 向您发出的警告。在您的情况下,它正在发生,因为getUrl 是异步的,并且在解决它之后设置了videoLink

我的意思是你不应该太担心,因为正在发生的事情是你的组件正在卸载,然后一个小操作“泄漏”(即setVideoLink(link as string))。

当您处理事件侦听器或间隔时,内存泄漏令人担忧。

即便如此,如果您担心这种行为,或者如果您对警告过于困扰,您可以创建一个逻辑,在触发 setState 调用之前检查您的组件是否已安装:

import { FC, useEffect, useState } from 'react';
import ReactPlayer from 'react-player';
import { FeedVideoProps } from '../../utils/types/interfaces';
import { getDecodedMedia } from '../../utils/helpers/getS3URL';

const FeedVideo: FC<FeedVideoProps> = ({ s3Key }: FeedVideoProps) => {
  const [videoLink, setVideoLink] = useState<string>('');
  const [isPlaying, setIsPlaying] = useState<boolean>(true);

  const getURL = async (key: string, isMounted: boolean) => {
    const link: string | object = await getDecodedMedia(key);
    if (isMounted) setVideoLink(link as string);
  };

  useEffect(() => {
    let isMounted = true;
    const abortController = new AbortController();
    getURL(s3Key, isMounted).then(() => abortController.abort());
    return () => {
      abortController.abort();
      isMounted = false;
    };
  }, [s3Key]);

  return (
    <ReactPlayer
      stopOnUnmount={true}
      className={'react-player'}
      controls={true}
      url={videoLink}
      playing={isPlaying}
    />
  );
};

export default FeedVideo;

【讨论】:

    【解决方案2】:
      const getURL = async (key: string): Promise<string> => {
        try {
          const link: string | object = await getDecodedMedia(key);
          return (link as string) || '';
        } catch (e) {
          throw new Error(e);
        }
      };
    
      useEffect(() => {
        let feedVideoMounted = true;
        getURL(s3Key).then((link) => {
          if (feedVideoMounted && link) {
            setVideoLink(link);
          }
        });
        return () => {
          feedVideoMounted = false;
        };
      }, [s3Key]);
    

    所以,我通过将逻辑更改为此解决了这个问题,并且成功了!

    【讨论】:

      猜你喜欢
      • 2021-05-05
      • 2020-05-15
      • 2019-10-29
      • 2020-01-15
      • 2021-03-25
      • 2022-06-10
      • 2022-06-10
      • 2020-06-28
      • 2020-09-10
      相关资源
      最近更新 更多