React项目中Material UI弹窗无法在当前页面打开的问题求助
解决Material UI Dialog在当前页面弹窗而非跳转路由的问题
这个问题的核心是你之前把Dialog做成了独立路由,导致点击后直接跳转页面。我们可以通过状态共享的方式,让Dialog在当前页面(Home/About)之上弹出,而不是跳转到新路由。下面是具体的修改步骤和代码:
1. 把Dialog的控制状态提升到App组件
App是SideMenu、Home、About的父组件,我们在这里维护Dialog的显示状态,这样所有子组件都能共享这个状态来控制弹窗:
// App.js import React, { useState } from "react"; import "./styles.css"; import { BrowserRouter, Route, Switch } from "react-router-dom"; import Home from "./home"; import About from "./about"; import Dialog from "./dialog"; import SideMenu from "./sidemu"; export default function App() { // 新增:控制Dialog显示的状态 const [dialogOpen, setDialogOpen] = useState(false); // 打开Dialog的方法 const openDialog = () => { setDialogOpen(true); }; // 关闭Dialog的方法 const closeDialog = () => { setDialogOpen(false); }; return ( <div className="App"> <BrowserRouter> {/* 把打开Dialog的方法传给SideMenu */} <SideMenu openDialog={openDialog} /> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/about" component={About} /> </Switch> {/* 在路由外层渲染Dialog,传递控制属性 */} <Dialog open={dialogOpen} onClose={closeDialog} /> </BrowserRouter> </div> ); }
2. 修改SideMenu,替换Link为点击事件触发弹窗
原来的Link会触发路由跳转,我们把它改成普通的列表项,点击时调用父组件传过来的openDialog方法,同时自动关闭侧边栏:
// SideMenu.js import React from 'react'; import './styles.css'; import { Link } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import Drawer from '@material-ui/core/Drawer'; import { List, ListItemIcon, ListItem, ListItemText } from '@material-ui/core'; import MenuRoundedIcon from '@material-ui/icons/MenuRounded'; import HomeRoundedIcon from '@material-ui/icons/HomeRounded'; import MenuBookRoundedIcon from '@material-ui/icons/MenuBookRounded'; const useStyles = makeStyles({ list: { width: 250, }, fullList: { width: 'auto', }, }); // 新增:接收父组件传来的openDialog方法 export default function TemporaryDrawer({ openDialog }) { const classes = useStyles(); const [state, setState] = React.useState({ top: false, left: false, bottom: false, right: false, }); const toggleDrawer = (side, open) => event => { if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { return; } setState({ ...state, [side]: open }); }; const sideList = side => ( <div className={classes.list} role="presentation" onClick={toggleDrawer(side, false)} onKeyDown={toggleDrawer(side, false)} > <List> <Link className="right-menu-data" to="/"> <ListItem button> <ListItemIcon> <HomeRoundedIcon /> </ListItemIcon> <ListItemText>Home</ListItemText> </ListItem> </Link> <Link className="right-menu-data" to="/about"> <ListItem button> <ListItemIcon> <MenuBookRoundedIcon /> </ListItemIcon> <ListItemText>About us</ListItemText> </ListItem> </Link> {/* 修改:去掉Link,改成点击触发弹窗+关闭侧边栏 */} <ListItem button onClick={() => { openDialog(); // 打开注册弹窗 toggleDrawer(side, false)(); // 关闭侧边栏 }}> <ListItemIcon> <MenuBookRoundedIcon /> </ListItemIcon> <ListItemText>User Registration</ListItemText> </ListItem> </List> </div> ); return ( <div> <MenuRoundedIcon className="careerpedia-menu-bars" onClick={toggleDrawer('right', true)} /> <Drawer anchor="right" open={state.right} onClose={toggleDrawer('right', false)}> {sideList('right')} </Drawer> </div> ); }
3. 调整Dialog组件,改成受控组件
原来的Dialog自己维护显示状态,现在改成由父组件传递open和onClose属性来控制,让它成为一个纯展示的组件:
// Dialog.js import React from 'react'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; // 新增:接收父组件传来的open和onClose属性 export default function AlertDialog({ open, onClose }) { return ( <div> <Dialog open={open} onClose={onClose} aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description" > <DialogTitle id="alert-dialog-title">{"User Registration"}</DialogTitle> <DialogContent> <DialogContentText id="alert-dialog-description"> 这里可以放置你的用户注册表单内容 </DialogContentText> </DialogContent> <DialogActions> <Button onClick={onClose} color="primary"> Cancel </Button> <Button onClick={onClose} color="primary" autoFocus> Register </Button> </DialogActions> </Dialog> </div> ); }
为什么这样改?
- 状态提升到App后,不管当前是Home还是About页面,都能共享Dialog的显示状态,确保弹窗在当前页面之上弹出
- 移除了
/dialog路由,避免跳转页面,保持当前页面的路由状态不变 - Dialog变成受控组件,完全由父组件控制显示隐藏,逻辑更清晰,也更容易扩展后续功能
这样修改后,点击侧边栏的“用户注册”就会在当前页面弹出Dialog,而不会跳转到新页面了。
内容的提问来源于stack exchange,提问作者Manu Panduu
相关产品推荐
相关产品推荐

