为什么点击按钮后 MUI 对话框不关闭?

huangapple go评论111阅读模式
英文:

why doesn't mui dialog close on button click?

问题

在我的React项目中,我有一个对话框,可以全屏打开,但在点击关闭图标按钮时无法关闭。以下是相关代码部分:

打开对话框的组件:

interface IContentCardProps {
  content: IContentProps;
}

const ContentCard = ({ content }: IContentCardProps) => {
  const { user } = useUser();
  const [open, setOpen] = useState<boolean>(false);

  return (
    <Box
      p={2}
      height="300px"
      maxWidth="250px"
      display="flex"
      flexDirection="column"
      justifyContent="space-between"
      border={`1px solid ${blue.main}`}
      sx={{
        cursor: "pointer",
        ":hover": { boxShadow: `0px 0px 3px 1px ${blue.main}` },
      }}
      onClick={() => setOpen(true)}
    >
      <Typography
        variant="body1"
        gutterBottom
        fontWeight={700}
        color={blue.main}
      >
        {content?.title}
      </Typography>
      <Typography
        variant="caption"
        marginBottom={1}
        lineHeight={1.6}
        textOverflow="ellipsis"
        display="-webkit-box "
        overflow="hidden"
        sx={{ WebkitLineClamp: 8, WebkitBoxOrient: "vertical" }}
      >
        {content?.description}
      </Typography>
      <Box pt={1} display="flex" alignItems="center" borderTop={`1px solid ${grey.extraLight}`}>
        <SvgIcon component={AccessTimeOutlinedIcon} sx={{ mr: 1 }} />
        <Typography variant="caption" fontWeight={700}>
          <span>{content?.duration}</span> min
        </Typography>
      </Box>
      <ContentDialog open={open} setOpen={setOpen} />
    </Box>
  );
};

export default ContentCard;

对话框组件:

const Transition = forwardRef(function Transition(
  props: TransitionProps & {
    children: React.ReactElement;
  },
  ref: React.Ref<unknown>,
) {
  return <Slide direction="left" ref={ref} {...props} />;
});

interface IContentDialogProps {
  open: boolean;
  setOpen: React.Dispatch<React.SetStateAction<boolean>>;
}

const ContentDialog = ({ open, setOpen }: IContentDialogProps) => {
  return (
    <>
      <Dialog fullScreen open={open} onClose={() => setOpen(false)} TransitionComponent={Transition}>
        <AppBar sx={{ position: "relative", backgroundColor: blue.main }}>
          <Toolbar>
            <IconButton edge="start" color="inherit" onClick={() => setOpen(false)} aria-label="close">
              <CloseIcon />
            </IconButton>
          </Toolbar>
        </AppBar>
        <Box>content</Box>
      </Dialog>
    </>
  );
};

在这里,setOpen 似乎在对话框上不起作用,我不知道为什么会这样。如果有人有任何想法,那就太好了!

英文:

In my React project I have a dialog that opens full screen but does not close when clicking on the close icon button. <br />

The component opening the Dialog :

interface IContentCardProps {
content: IContentProps;
}
const ContentCard = ({ content }: IContentCardProps) =&gt; {
const { user } = useUser();
const [open, setOpen] = useState&lt;boolean&gt;(false);
return (
&lt;Box
p={2}
height=&quot;300px&quot;
maxWidth=&quot;250px&quot;
display=&quot;flex&quot;
flexDirection=&quot;column&quot;
justifyContent=&quot;space-between&quot;
border={`1px solid ${blue.main}`}
sx={{
cursor: &quot;pointer&quot;,
&quot;:hover&quot;: { boxShadow: `0px 0px 3px 1px ${blue.main}` },
}}
onClick={() =&gt; setOpen(true)}
&gt;
&lt;Typography
variant=&quot;body1&quot;
gutterBottom
fontWeight={700}
color={blue.main}
&gt;
{content?.title}
&lt;/Typography&gt;
&lt;Typography
variant=&quot;caption&quot;
marginBottom={1}
lineHeight={1.6}
textOverflow=&quot;ellipsis&quot;
display=&quot;-webkit-box &quot;
overflow=&quot;hidden&quot;
sx={{ WebkitLineClamp: 8, WebkitBoxOrient: &quot;vertical&quot; }}
&gt;
{content?.description}
&lt;/Typography&gt;
&lt;Box pt={1} display=&quot;flex&quot; alignItems=&quot;center&quot; borderTop={`1px solid ${grey.extraLight}`}&gt;
&lt;SvgIcon component={AccessTimeOutlinedIcon} sx={{ mr: 1 }} /&gt;
&lt;Typography variant=&quot;caption&quot; fontWeight={700}&gt;
&lt;span&gt;{content?.duration}&lt;/span&gt; min
&lt;/Typography&gt;
&lt;/Box&gt;
&lt;ContentDialog open={open} setOpen={setOpen} /&gt;
&lt;/Box&gt;
);
};
export default ContentCard;

The dialog component :

const Transition = forwardRef(function Transition(
props: TransitionProps &amp; {
children: React.ReactElement;
},
ref: React.Ref&lt;unknown&gt;,
) {
return &lt;Slide direction=&quot;left&quot; ref={ref} {...props} /&gt;;
});
interface IContentDialogProps {
open: boolean;
setOpen: React.Dispatch&lt;React.SetStateAction&lt;boolean&gt;&gt;;
}
const ContentDialog = ({ open, setOpen }: IContentDialogProps) =&gt; {
return (
&lt;&gt;
&lt;Dialog fullScreen open={open} onClose={() =&gt; setOpen(false)} TransitionComponent={Transition}&gt;
&lt;AppBar sx={{ position: &quot;relative&quot;, backgroundColor: blue.main }}&gt;
&lt;Toolbar&gt;
&lt;IconButton edge=&quot;start&quot; color=&quot;inherit&quot; onClick={() =&gt; setOpen(false)} aria-label=&quot;close&quot;&gt;
&lt;CloseIcon /&gt;
&lt;/IconButton&gt;
&lt;/Toolbar&gt;
&lt;/AppBar&gt;
&lt;Box&gt; content&lt;/Box&gt;
&lt;/Dialog&gt;
&lt;/&gt;
);
};

SetOpen does not seem to work on the Dialog and I don't know why... <br />
If anyone has an idea that would be great ! <br />

答案1

得分: 0

点击关闭按钮会触发点击事件,该事件也可能会冒泡并意外地触发父元素上的点击事件。这会导致在 ContentCard 中的 <Box> 元素上执行 onClick={() =&gt; setOpen(true)} 函数。为了防止这种情况发生,您可以在关闭按钮的点击事件上使用 stopPropagation。如下所示:

onClick={(e) =&gt; {
  e.stopPropagation();
  setOpen(false);
}}

此外,因为您主要是在 ContentDialog 中关闭对话框,您可以在 ContentCard 中创建该函数。然后,您可以传递该函数而不是 setState 函数。

如果您不想使用 stopPropagation,您可以简单地将 ContentDialog 放在 Box 元素之外。这样,对话框将不再是盒子元素的直接子元素。如下所示:

function ContentCard({ content }) {
  const [open, setOpen] = useState(false);

  const onClose = (e) =&gt; setOpen(false);

  return (
    &lt;&gt;
      &lt;Box&gt;&lt;/Box&gt;
      &lt;ContentDialog open={open} onClose={onClose} /&gt;
    &lt;/&gt;
  );
}
英文:

Clicking the close button triggers a click event, which can also bubble up and inadvertently trigger a click event on the parent element. This results in the execution of the onClick={() =&gt; setOpen(true)} function on the <Box> element within ContentCard. To prevent this, you can use stopPropagation on the close button's click event. Here's how:

onClick={(e) =&gt; {
  e.stopPropagation();
  setOpen(false);
}}

Additionally, because you're mainly closing the dialog in ContentDialog, you can create that function in ContentCard. Then, you can pass that instead of setState function.

为什么点击按钮后 MUI 对话框不关闭?

If you prefer not to use stopPropagation, you can simply place the ContentDialog outside the Box element. This way, the dialog won't be a direct child of the box element anymore. Here's how you can do it:

function ContentCard({ content }) {
  const [open, setOpen] = useState(false);

  const onClose = (e) =&gt; setOpen(false);

  return (
    &lt;&gt;
      &lt;Box&gt;&lt;/Box&gt;
      &lt;ContentDialog open={open} onClose={onClose} /&gt;
    &lt;/&gt;
  );
}

huangapple
  • 本文由 发表于 2023年8月10日 22:17:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定