[英]ReactJS: How do I open an Material-UI Accordion programmatically?
[英]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
組件,這意味着我們可以向下傳遞上下文數據,以便其他組件可以引用,在這種情況下,我們希望向下傳遞createDialog
和closeDialog
。
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>
);
}
你可以在這里玩現場演示
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.