簡體   English   中英

Material-UI - 如何以命令式/編程方式打開 Dialog

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

通常這就是您使用 Material-UI 的Dialog 下面的代碼取自 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>
  );
}

但我希望它命令式地創建Dialog ,有點像火了然后忘記了。 我不想在需要創建它們時Dialog組件嵌入到其他組件中。 理想情況下,我想這樣稱呼它

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

所以我的組件定義看起來像這樣

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>
  );
}

您可以使用 React 的Provider模式重用對話框。 React 官方文檔已經解釋的很詳細了,這里就不再贅述了。

在這種情況下,首先創建一個自定義Provider組件,我將調用DialogProvider 該組件將管理本地狀態下的Dialog列表。

const DialogContext = React.createContext();

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

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

如您所見,我們在這里有一個對話框數組,它包含在渲染時將映射到實際<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>
  );
}

<DialogContainer/><Dialog/>的父組件。 把任何你想重用的東西放進去 這是讓您入門的最低示例。

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

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

我們可以像往常一樣使用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 });
  });
};

但是當我們在這里定義它們時,我們如何在其他組件中調用它們呢? 好吧,請記住我們在這里使用了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>
);

我們差不多完成了,現在我們需要將DialogProvider添加到組件樹中。

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

但是在我們可以使用它們之前,我們應該創建一個鈎子來輕松地從父級訪問上下文。 所以在你的DialogProvider.jsx

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

現在我們可以像這樣使用它。

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>
  );
}

現場演示

你可以在這里玩現場演示

編輯 DialogProvider

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM