【问题标题】:Closing Material UI Dialog from child component triggers parent's Dialog to open从子组件关闭 Material UI Dialog 会触发父 Dialog 打开
【发布时间】:2021-05-28 13:04:47
【问题描述】:

我有 2 个对话框,一个在外部范围(父级),一个作为子级。

export default function App() {
  const [parentDialogOpen, setParentDialogOpen] = useState(false);
  const [childDialogOpen, setChildDialogOpen] = useState(false);

  const handleParentClick = () => {
    setParentDialogOpen(true);
  };

  const handleChildClick = (e) => {
    e.stopPropagation();
    setChildDialogOpen(true);
  };

  return (
    <div className="App">
      <Dialog
        open={parentDialogOpen}
        onClose={() => setParentDialogOpen(false)}
      >
        <Box p={4}>Parent Dialog</Box>
      </Dialog>

      <Box bgcolor="red" p={2} onClick={handleParentClick}>
        <Dialog
          open={childDialogOpen}
          onClose={(e) => setChildDialogOpen(false)}
        >
          <Box p={2}>Child Dialog</Box>
        </Dialog>

        <button onClick={handleChildClick}>Child</button>
      </Box>
    </div>
  );
}

当我点击按钮时,它会打开一个对话框(子对话框),但当我关闭它时,会弹出父对话框。我的预期行为是单击子按钮不应在父级上触发onClick 事件(因为我已将e.stopPropagation() 添加到子级的onClick 处理程序中)

handleChildClick 上添加e.stopPropagation() 确实会阻止事件传播到父母的onClick,但是当我关闭对话框时,父母的onClick 仍然会触发。

我也尝试将e.stopPropagation() 添加到子对话框的onClose,但没有帮助。

虽然将子对话框移动到与父对话框相同的级别使其按预期工作,但我不能这样做,因为在我的(真实)代码中,我必须动态渲染子组件,子组件可能有它自己的对话框。

有没有办法解决这个问题?

[更新]:似乎父对话框的onClick 事件在子对话框打开时单击任何位置时也会触发。例如,单击 INSIDE 子对话框将触发父对话框的 onClick(不关闭子对话框)

这是一个代码沙箱:https://codesandbox.io/embed/eloquent-hypatia-nuksu?fontsize=14&hidenavigation=1&theme=dark

【问题讨论】:

  • handleParentClick 不绑定到父对话,它绑定到子对话的父 div。这是当您单击子对话框中的任意位置时触发的自然行为

标签: reactjs material-ui


【解决方案1】:

只需在 Dialog 的 onClick 事件中停止传播(见下文)


import "./styles.css";
import { Box, Dialog } from "@material-ui/core";
import { useState } from "react";

export default function App() {
  const [parentDialogOpen, setParentDialogOpen] = useState(false);
  const [childDialogOpen, setChildDialogOpen] = useState(false);

  const handleParentClick = () => {
    setParentDialogOpen(true);
  };

  const handleChildClick = (e) => {
    e.stopPropagation();
    setChildDialogOpen(true);
  };

  return (
    <div className="App">
      <Dialog
        open={parentDialogOpen}
        onClose={() => setParentDialogOpen(false)}
      >
        <Box p={4}>Parent Dialog</Box>
      </Dialog>

      <Box bgcolor="red" p={2} onClick={handleParentClick}>
        <Dialog
          open={childDialogOpen}
          onClick={(e) => e.stopPropagation()}
          onClose={(e) => setChildDialogOpen(false)}
        >
          <Box p={2}>Child Dialog</Box>
        </Dialog>

        <button onClick={handleChildClick}>Child</button>
      </Box>
    </div>
  );
}

【讨论】:

  • 这确实解决了我的问题。但是,是否有其他解决方案我不需要在子对话框中添加此 onClick 事件?否则,每个子对话框(可以在其他地方使用)总是需要添加这个特殊的onClick 事件,而不是使用大量组件和团队时的最佳方案。
  • 如果您想避免使用 onClick,可以尝试类似的方法:codesandbox.io/s/white-flower-0m1vp?file=/src/App.js
  • 将子对话框移出父容器对我来说不是一个选项,因为这将动态呈现(如问题中所述)。但是,我会接受第一个解决方案作为答案,因为我们可以通过 muiTheme 覆盖所有 material-ui Dialog 来完成。
【解决方案2】:

如果您的目标是在孩子关闭时触发父对话框打开,您可以使用以下内容;

...
...
 <Dialog
          open={childDialogOpen}
          onClose={(e) => {
            setChildDialogOpen(false);
            setParentDialogOpen(true);
            }}
        >

那就永远摆脱handleParentClick

【讨论】:

  • 我的目标是防止在孩子关闭时打开父对话框。
猜你喜欢
  • 2021-09-17
  • 2021-10-12
  • 2020-09-03
  • 2018-12-26
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
相关资源
最近更新 更多