简体   繁体   English

Material-UI - 如何以命令式/编程方式打开 Dialog

[英]Material-UI - How to open Dialog imperatively/programmatically

Normally this is how you use Material-UI's Dialog .通常这就是您使用 Material-UI 的Dialog The code below is taken from Material-UI's docs下面的代码取自 Material-UI 的文档

export default function AlertDialog() {
  const [open, setOpen] = React.useState(false);
  const handleClickOpen = () => setOpen(true);
  const handleClose = () => setOpen(false);

  return (
    <div>
      <Button variant="outlined" color="primary" onClick={handleClickOpen}>
        Open Dialog
      </Button>
      <Dialog open={open} onClose={handleClose}>
       {...}
      </Dialog>
    </div>
  );
}

But I want it to create the Dialog imperatively, sort of like fire and forget.但我希望它命令式地创建Dialog ,有点像火了然后忘记了。 I do not want to embed the Dialog component in other components whenever I need to create them.我不想在需要创建它们时Dialog组件嵌入到其他组件中。 Ideally I'd want to call it like this理想情况下,我想这样称呼它

createDialog(<>
   <h1>My Dialog</h1>
   <span>My dialog content</span>
   <button onClick={() => closeDialog()}>Close</button>
</>)

So my component definition'd look like this所以我的组件定义看起来像这样

const createDialog = () => {
   // ???
}
const closeDialog = () => {
   // ???
}
export default function AlertDialog() {
  const [open, setOpen] = React.useState(false);
  const handleClickOpen = () => setOpen(true);
  const handleClose = () => {
     createDialog(<>
        <h1>My Dialog</h1>
        <span>My dialog content</span>
        <button onClick={() => closeDialog()}>Close</button>
     </>)
  };

  return (
    <Button variant="outlined" color="primary" onClick={handleClickOpen}>
      Open Dialog
    </Button>
  );
}

You can reuse dialogs using React's Provider pattern.您可以使用 React 的Provider模式重用对话框。 The official React document has explained in good detail so I won't cover it again here. React 官方文档已经解释的很详细了,这里就不再赘述了。

First create a custom Provider component in this case I'll call DialogProvider .在这种情况下,首先创建一个自定义Provider组件,我将调用DialogProvider This component will manage a list of Dialog s in local state.该组件将管理本地状态下的Dialog列表。

const DialogContext = React.createContext();

export default function DialogProvider({ children }) {
  const [dialogs, setDialogs] = React.useState([]);

  return (
    <DialogContext.Provider {...}>
      {children}
    </DialogContext.Provider>
  );
}

As you can see, we have an array of dialogs here, it contains the dialog props that will be mapped to the actually <Dialog /> component when rendering.如您所见,我们在这里有一个对话框数组,它包含在渲染时将映射到实际<Dialog />组件的对话框道具。

export default function DialogProvider({ children }) {
  const [dialogs, setDialogs] = React.useState([]);

  return (
    <DialogContext.Provider {...}>
      {children}
      {dialogs.map((dialog, i) => {
        return <DialogContainer key={i} {...dialog} />;
      })}
    </DialogContext.Provider>
  );
}

The <DialogContainer/> is the parent component of the <Dialog/> . <DialogContainer/><Dialog/>的父组件。 Put anything that you want to be reusable in there .把任何你想重用的东西放进去 Here is a minimum example to get you started.这是让您入门的最低示例。

function DialogContainer(props: DialogContainerProps) {
  const { children, open, onClose, onKill } = props;

  return (
    <Dialog open={open} onClose={onClose} onExited={onKill}>
      {children}
    </Dialog>
  );
}

We can create and remove the dialog using setState as normal.我们可以像往常一样使用setState创建和删除对话框。

const [dialogs, setDialogs] = React.useState([]);

const createDialog = (option) => {
  const dialog = { ...option, open: true };
  setDialogs((dialogs) => [...dialogs, dialog]);
};

const closeDialog = () => {
  setDialogs((dialogs) => {
    const latestDialog = dialogs.pop();
    if (!latestDialog) return dialogs;
    if (latestDialog.onClose) latestDialog.onClose();
    return [...dialogs].concat({ ...latestDialog, open: false });
  });
};

But how do we call them in other components when we defined them here?但是当我们在这里定义它们时,我们如何在其他组件中调用它们呢? Well, remember we're using Provider component here, which means we can pass the context data down so other components can reference, in this case we want to pass the createDialog and closeDialog down.好吧,请记住我们在这里使用了Provider组件,这意味着我们可以向下传递上下文数据,以便其他组件可以引用,在这种情况下,我们希望向下传递createDialogcloseDialog

const [dialogs, setDialogs] = React.useState([]);
const createDialog = (option) => {/*...*/};
const closeDialog = () => {/*...*/};
const contextValue = React.useRef([createDialog, closeDialog]);

return (
  <DialogContext.Provider value={contextValue.current}>
    {children}
    {dialogs.map((dialog, i) => ...)}
  </DialogContext.Provider>
);

We're almost done here, now we need to add the DialogProvider to the component tree.我们差不多完成了,现在我们需要将DialogProvider添加到组件树中。

export default function App() {
  return (
    <DialogProvider>
      <App {...} />
    </DialogProvider>
  );
}

But before we can use them, we should create a hook to easily access the context from the parent.但是在我们可以使用它们之前,我们应该创建一个钩子来轻松地从父级访问上下文。 So in your DialogProvider.jsx所以在你的DialogProvider.jsx

export const useDialog = () => React.useContext(DialogContext);

Now we can use it like this.现在我们可以像这样使用它。

import { useDialog } from "./DialogProvider";

export default function Content() {
  const [openDialog, closeDialog] = useDialog();
  const onOpenDialog = () => {
    openDialog({
      children: (
        <>
          <DialogTitle>This dialog is opened imperatively</DialogTitle>
          <DialogContent>Some content</DialogContent>
          <DialogActions>
            <Button color="primary" onClick={closeDialog}>Close</Button>
          </DialogActions>
        </>
      )
    });
  };

  return (
    <Button variant="contained" onClick={onOpenDialog}>
      Show dialog
    </Button>
  );
}

Live Demo现场演示

You can play around in the live demo here你可以在这里玩现场演示

编辑 DialogProvider

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ReactJS:如何以编程方式打开 Material-UI 手风琴? - ReactJS: How do I open an Material-UI Accordion programmatically? 如何在 Material-UI 中将 position 对话框置顶 - How to position Dialog to top in Material-UI 如何有条件地渲染对话框 Material-ui - how to conditionally render dialog Material-ui 如何使 Material-UI 对话框可调整大小 - How to make Material-UI Dialog resizable reactjs中打开对话框时如何在material-ui对话框的state中设置道具数据 - How to set the props data in the state of material-ui dialog when the dialog open in react js 使用 redux 打开 state 时 Material-ui 对话框闪烁 - Material-ui dialog flickering when using redux for open state 如何在 Meteor/React 中打开和关闭 Material-UI 对话框? - How do I open and close a Material-UI Dialog in Meteor/React? 如何将材料表与 Material-UI 对话框相结合? (反应JS) - How to combine Material-table with Material-UI Dialog? (ReactJS) ReactJS + Material-UI:如何在每个TableRow中使用Material-UI的FlatButton和Dialog? - ReactJS + Material-UI: How to use Material-UI’s FlatButton and Dialog in each TableRow? ReactJS和Material-UI:如何仅突出Material-UI内部的内容 <Dialog> 而不是整个页面? - ReactJS & Material-UI: How to highlight just content inside Material-UI's <Dialog> and not the whole page?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM