【问题标题】:React Hooks setInterval memory leakReact Hooks setInterval 内存泄漏
【发布时间】:2020-07-15 09:20:36
【问题描述】:

我创建了一个倒数计时器组件,它将数据传递给另一个组件,我使用setTimeout。该组件按预期工作,但我的控制台中出现警告:

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

当我在useEffect 中使用setTimeout 时,我尝试在返回函数中添加clearInterval,但这似乎没有帮助。您可以在下面找到我的组件:

export default function createEvent(WrappedComponent) {
  const Event = props => {
    const [{ endDate }] = useState(props);
    const [days, setDays] = useState('');
    const [hours, setHours] = useState('');
    const [minutes, setMinutes] = useState('');
    const [seconds, setSeconds] = useState('');

    const interval = useRef();

    useEffect(() => {
      interval.current = setInterval(() => {
        const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
        const then = moment(date, 'MM DD YYYY, h:mm a');
        const now = moment();
        const countdown = moment(then - now);
        const daysFormat = countdown.format('D');
        const hoursFormat = countdown.format('HH');
        const minutesFormat = countdown.format('mm');
        const secondsFormat = countdown.format('ss');

        setDays(`${daysFormat} days`);
        setHours(hoursFormat);
        setMinutes(minutesFormat);
        setSeconds(secondsFormat);

        return () => {
          clearInterval(interval.current);
          interval.current = null;
        };
      }, 1000);
    }, []);

    return (
      <WrappedComponent
        days={days}
        hours={hours}
        minutes={minutes}
        seconds={seconds}
        {...props}
      />
    );
  };

  return Event;
}

如果我尝试通过在最后一个下方添加另一个 useEffect 来从其他地方模仿 clear,如下所示:

  useEffect(() => {
    setTimeout(() => clearInterval(interval.current), 15000)
  }, [])

警告消失,但倒计时不再起作用。那么如何才能做到这一点,不影响倒计时并清除警告呢?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    useEffect 钩子 [1] 的清理函数需要从您提供给 useEffect 的函数中返回。您将在您提供给setInterval 的函数中返回您的清理函数。

    useEffect(() => {
      interval.current = setInterval(() => {
        const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
        const then = moment(date, 'MM DD YYYY, h:mm a');
        const now = moment();
        const countdown = moment(then - now);
        const daysFormat = countdown.format('D');
        const hoursFormat = countdown.format('HH');
        const minutesFormat = countdown.format('mm');
        const secondsFormat = countdown.format('ss');
    
        setDays(`${daysFormat} days`);
        setHours(hoursFormat);
        setMinutes(minutesFormat);
        setSeconds(secondsFormat);
      }, 1000);
    
      // move clean up function to here:
      return () => {
        clearInterval(interval.current);
        interval.current = null;
      };
    }, []);
    

    [1]https://reactjs.org/docs/hooks-effect.html

    【讨论】:

    • 天哪,我怎么没注意到...)) 我疯了...谢谢你注意到@sdgluck
    【解决方案2】:

    effects 不需要 createRef。并且返回应该是after the interval。

    useEffect(() => {
          const timer = setInterval(() => {
            const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
            const then = moment(date, 'MM DD YYYY, h:mm a');
            const now = moment();
            const countdown = moment(then - now);
            const daysFormat = countdown.format('D');
            const hoursFormat = countdown.format('HH');
            const minutesFormat = countdown.format('mm');
            const secondsFormat = countdown.format('ss');
    
            setDays(`${daysFormat} days`);
            setHours(hoursFormat);
            setMinutes(minutesFormat);
            setSeconds(secondsFormat);
    
          }, 1000);
    
           return () => {
              clearInterval(timer);
            };
        }, []);
    

    【讨论】:

      【解决方案3】:
      useEffect(() => {
            interval.current = setInterval(() => {
              const date = moment.unix(endDate).format('MM DD YYYY, h:mm a');
              const then = moment(date, 'MM DD YYYY, h:mm a');
              const now = moment();
              const countdown = moment(then - now);
              const daysFormat = countdown.format('D');
              const hoursFormat = countdown.format('HH');
              const minutesFormat = countdown.format('mm');
              const secondsFormat = countdown.format('ss');
      
              setDays(`${daysFormat} days`);
              setHours(hoursFormat);
              setMinutes(minutesFormat);
              setSeconds(secondsFormat);
            }, 1000);
      
        // Attention : return function cleanup for the function used in useEffect()
        return () => {
            clearInterval(interval.current);
            interval.current = null;
          };
      }, []);
      

      您可以在此处查看我的完整答案“Cleanup memory leaks on an Unmounted Component in React Hooks”:https://stackoverflow.com/a/59956926/4386148

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 2019-03-09
        • 1970-01-01
        • 2020-10-29
        • 2014-02-08
        相关资源
        最近更新 更多