MUI确认对话框关闭后未重置输入状态的修复方案咨询
问题描述
基于Material-UI的确认对话框示例开发,当前示例包含三个文本输入框,实际应用会有更多输入项。遇到的问题是:修改输入框内容后点击取消按钮,重新打开对话框时,修改后的内容仍保留,未恢复原始值。
已知问题源于单独管理每个输入框的状态而非直接修改layout,但layout结构复杂且嵌套深,希望单独管理各输入状态,仅在保存时一次性更新layout,而非每次输入变更都修改layout,求修复方案。
示例代码
App.js
import ConfirmDialog from "./ConfirmDialog"; export default function App() { return ( <div> <ConfirmDialog /> </div> ); }
ConfirmDialog.js
import * as React from "react"; import PropTypes from "prop-types"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import DialogTitle from "@mui/material/DialogTitle"; import DialogContent from "@mui/material/DialogContent"; import DialogActions from "@mui/material/DialogActions"; import Dialog from "@mui/material/Dialog"; import TextField from "@mui/material/TextField"; function ConfirmationDialogRaw(props) { const { onClose, layout: layoutProp, open, ...other } = props; const [layout, setLayout] = React.useState(layoutProp); // 实际应用会有更多输入项 const [title, setTitle] = React.useState(layout.title.text); const [firstName, setFirstName] = React.useState(layout.name.first); const [lastName, setLastName] = React.useState(layout.name.last); React.useEffect(() => { if (!open) { setLayout(layoutProp); } }, [layoutProp, open]); const handleCancel = () => { onClose(); }; const handleSave = () => { onClose({ title: { text: title }, name: { first: firstName, last: lastName } }); }; return ( <Dialog sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }} maxWidth="xs" open={open} {...other} > <DialogTitle>Layout</DialogTitle> <DialogContent dividers> <TextField margin="dense" id="title-label" label="Title" type="text" fullWidth variant="standard" value={title} onChange={(event) => setTitle(event.target.value)} /> <TextField margin="dense" id="first-name-label" label="First Name" type="text" fullWidth variant="standard" value={firstName} onChange={(event) => setFirstName(event.target.value)} /> <TextField margin="dense" id="last-name-label" label="Last Name" type="text" fullWidth variant="standard" value={lastName} onChange={(event) => setLastName(event.target.value)} /> </DialogContent> <DialogActions> <Button autoFocus onClick={handleCancel}> Cancel </Button> <Button onClick={handleSave}> Save </Button> </DialogActions> </Dialog> ); } ConfirmationDialogRaw.propTypes = { onClose: PropTypes.func.isRequired, open: PropTypes.bool.isRequired, value: PropTypes.string.isRequired }; const defaultLayout = { title: { text: "Default title" }, name: { first: "John", last: "Doe" } }; export default function ConfirmationDialog() { const [open, setOpen] = React.useState(false); const [layout, setLayout] = React.useState(defaultLayout); const handleOpen = () => { setOpen(true); }; const handleClose = (newLayout) => { setOpen(false); if (newLayout) { setLayout(newLayout); } }; return ( <Box> <Button variant="contained" onClick={handleOpen}> Open Dialog </Button> <ConfirmationDialogRaw id="layout-dialog" keepMounted open={open} onClose={handleClose} layout={layout} /> </Box> ); }
修复方案
问题核心是对话框关闭/重新打开时,未同步重置单独管理的输入状态。当前代码只重置了layout状态,但title、firstName等输入状态没有跟着更新。以下是两种可行方案:
方案一:打开对话框时同步输入状态
修改ConfirmationDialogRaw组件,监听open和layoutProp的变化,每次对话框打开时,从最新的layoutProp中重新初始化输入状态:
function ConfirmationDialogRaw(props) { const { onClose, layout: layoutProp, open, ...other } = props; // 移除多余的layout状态,直接以layoutProp为数据源 const [title, setTitle] = React.useState(''); const [firstName, setFirstName] = React.useState(''); const [lastName, setLastName] = React.useState(''); React.useEffect(() => { // 对话框打开时,加载最新的原始值 if (open) { setTitle(layoutProp.title.text); setFirstName(layoutProp.name.first); setLastName(layoutProp.name.last); } }, [layoutProp, open]); // handleCancel、handleSave及其余代码保持不变 }
方案二:点击取消时直接重置输入状态
在handleCancel中手动将所有输入状态重置为layoutProp的原始值,再关闭对话框:
const handleCancel = () => { // 重置为原始值 setTitle(layoutProp.title.text); setFirstName(layoutProp.name.first); setLastName(layoutProp.name.last); onClose(); };
针对大量输入项的优化建议
如果输入项很多,逐个声明状态会非常繁琐,可以用一个对象统一管理所有输入状态,减少重复代码:
function ConfirmationDialogRaw(props) { const { onClose, layout: layoutProp, open, ...other } = props; const [formState, setFormState] = React.useState({ title: layoutProp.title.text, firstName: layoutProp.name.first, lastName: layoutProp.name.last }); React.useEffect(() => { if (open) { setFormState({ title: layoutProp.title.text, firstName: layoutProp.name.first, lastName: layoutProp.name.last }); } }, [layoutProp, open]); // 统一处理输入变更 const handleInputChange = (field, value) => { setFormState(prev => ({ ...prev, [field]: value })); }; const handleSave = () => { onClose({ title: { text: formState.title }, name: { first: formState.firstName, last: formState.lastName } }); }; // 输入框的onChange改为: // onChange={(e) => handleInputChange('title', e.target.value)} // 其余输入框同理 }
这样既保留了单独管理输入状态的需求,又能确保取消时恢复原始值,同时避免了大量重复的状态声明。
内容的提问来源于stack exchange,提问作者Simon1
相关产品推荐
相关产品推荐

