如何避免 ReactJS 中屏幕尺寸变化时的内存泄漏

发布于 2025-01-20 03:38:43 字数 2905 浏览 0 评论 0原文

在Google Inspector中,在桌面和移动视图之间切换时,我会不断遇到内存泄漏错误(尽管如果我通过伸展而收缩/扩展屏幕)。错误消息是:

“在此处输入图像描述”

我不使用我知道的任何订阅或异步任务。我唯一能想到的可能会导致这件事,是在屏幕切换时,我的AlertDialog组件没有显示。那是因为它只是有条件地渲染的:

return (
    <Screen>
      {showDialog === true ? 
        <AlertDialog /> :
        <MainApp />
      }
    </Screen>
  );

如果更改时屏幕上的AlertDialog在屏幕上,则不会显示错误。

我的对话框的代码是:

import { useEffect, useState } from "react";
import { useWindowSize } from "src/hooks";

import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';

const AlertDialog = (props : any) => {

  const {innerWidth, innerHeight} = useWindowSize();
  const [openDialog, setOpenDialog] = useState(true);
  const [buttonStyle, setButtonStyle] = useState({});

  useEffect( () => {  // Needs b/c isn't working right in Styled
    setButtonStyle({
      width: Math.max(innerWidth/10, 100),
    });
  }, [innerWidth, innerHeight])

  const handleClick = (choseTrue : boolean) => {
    setOpenDialog(false);
    props.onClick(choseTrue);
  }

  return (
    <Dialog
      open={openDialog}
      onClose={() => null} // Use null to prevent it from closing until an option is chosen
      aria-labelledby="alert-dialog-title"
      aria-describedby="alert-dialog-description"
    >
      <DialogTitle id="alert-dialog-title" style={{textAlign: "center"}}>{"Set Device"}</DialogTitle>
      <DialogContent>
        <DialogContentText id="alert-dialog-description"> </DialogContentText>
      </DialogContent>
      <DialogActions>
        <button onClick={() => handleClick(true)} style={buttonStyle}>{props.choiceTrue}</button>
        <button onClick={() => handleClick(false)} style={buttonStyle}>{props.choiceFalse}</button>
      </DialogActions>
    </Dialog>
  );
};

export default AlertDialog;

这是我的屏幕调整大小。我很确定这是问题的来源,因为如果我在AlertDialog中评论usewindowsize行,没有错误:

import { useState, useEffect } from "react";

export const useWindowSize = () => {
  const [size, setSize] = useState<{
    innerWidth: number;
    innerHeight: number;
  }>({ ...window });

  useEffect(() => {
    const cb = (u: UIEvent) => {
      const w = u.target as Window;
      setSize({ ...w });
    };
    window.addEventListener("resize", cb, true);
    () => window.removeEventListener("resize", cb);
  }, []);

  return size;
};

为什么我会遇到此内存泄漏错误,以及如何避免它?

I keep getting memory leak errors when switching between desktop and mobile view in google inspector (though not if I shrink/expand the screen by stretching). The error message is:

enter image description here

I'm not using any subscriptions or asynchronous tasks I'm aware of. The only thing I can think of that might contribute to this is that at the time of the screen switching, my AlertDialog component isn't showing. That's because it's only conditionally rendered:

return (
    <Screen>
      {showDialog === true ? 
        <AlertDialog /> :
        <MainApp />
      }
    </Screen>
  );

The error doesn't show up if the AlertDialog is on screen at the time of the change.

The code for my dialog is:

import { useEffect, useState } from "react";
import { useWindowSize } from "src/hooks";

import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';

const AlertDialog = (props : any) => {

  const {innerWidth, innerHeight} = useWindowSize();
  const [openDialog, setOpenDialog] = useState(true);
  const [buttonStyle, setButtonStyle] = useState({});

  useEffect( () => {  // Needs b/c isn't working right in Styled
    setButtonStyle({
      width: Math.max(innerWidth/10, 100),
    });
  }, [innerWidth, innerHeight])

  const handleClick = (choseTrue : boolean) => {
    setOpenDialog(false);
    props.onClick(choseTrue);
  }

  return (
    <Dialog
      open={openDialog}
      onClose={() => null} // Use null to prevent it from closing until an option is chosen
      aria-labelledby="alert-dialog-title"
      aria-describedby="alert-dialog-description"
    >
      <DialogTitle id="alert-dialog-title" style={{textAlign: "center"}}>{"Set Device"}</DialogTitle>
      <DialogContent>
        <DialogContentText id="alert-dialog-description"> </DialogContentText>
      </DialogContent>
      <DialogActions>
        <button onClick={() => handleClick(true)} style={buttonStyle}>{props.choiceTrue}</button>
        <button onClick={() => handleClick(false)} style={buttonStyle}>{props.choiceFalse}</button>
      </DialogActions>
    </Dialog>
  );
};

export default AlertDialog;

This is my screen resize code. I'm pretty sure it's the source of the issue, since if I comment out the useWindowSize line in AlertDialog, there is no error:

import { useState, useEffect } from "react";

export const useWindowSize = () => {
  const [size, setSize] = useState<{
    innerWidth: number;
    innerHeight: number;
  }>({ ...window });

  useEffect(() => {
    const cb = (u: UIEvent) => {
      const w = u.target as Window;
      setSize({ ...w });
    };
    window.addEventListener("resize", cb, true);
    () => window.removeEventListener("resize", cb);
  }, []);

  return size;
};

Why am I getting this memory leak error, and how can I avoid it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如果没有你 2025-01-27 03:38:43

你需要从 useEffect 返回该清理函数的回调函数我之前已经写过这个钩子,这里是代码

如果你想要 useScreenSizeChecker Hook,

import { useState, useEffect, useCallback } from "react";

/** Default size is 768px */
export const useScreenSizeChecker = (width = 768):boolean => {
  const [sizeCheck, setSizeCheck] = useState(window.innerWidth < width);

  const checkSize = useCallback(() => {
    setSizeCheck(window.innerWidth < width);
  }, [width]);

  useEffect(() => {
    window.addEventListener("resize", checkSize);
    checkSize();
    return () => {
      window.removeEventListener("resize", checkSize);
    };
  }, [checkSize]);

  return sizeCheck;
};

you need to return the callback function from useEffect for that cleanup function

if you want to have useScreenSizeChecker Hook I have written this hook before here is the code

import { useState, useEffect, useCallback } from "react";

/** Default size is 768px */
export const useScreenSizeChecker = (width = 768):boolean => {
  const [sizeCheck, setSizeCheck] = useState(window.innerWidth < width);

  const checkSize = useCallback(() => {
    setSizeCheck(window.innerWidth < width);
  }, [width]);

  useEffect(() => {
    window.addEventListener("resize", checkSize);
    checkSize();
    return () => {
      window.removeEventListener("resize", checkSize);
    };
  }, [checkSize]);

  return sizeCheck;
};

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文