React复用Modal中submit函数无法获取最新text状态的问题
React Modal提交时无法获取最新输入值的解决方案
问题描述
在React中实现了一个可复用的Modal组件,将弹窗的标题、描述、提交函数及弹窗状态存入state。使用text状态收集Modal内的用户评论,输入时text能正常更新,但点击提交按钮时,提交函数无法获取text的最新值,期望提交时能打印出输入的评论内容。
相关代码
主组件
const defaultModal = { open: false, title: "", description: "", handleSubmit: null, }; const Parent = () => { const [modal, setModal] = useState(defaultModal); const [text, setText] = useState(""); const handleSubmit = () => { console.log(text + " in submit"); setModal(defaultModal); }; const handleDelete = () => { console.log(text + "in delete"); setModal(defaultModal); }; const openSubmitModal = () => { setModal(prev=>({ ...prev, open: true, title: "Are you sure to submit", description: "now you are submitting", handleSubmit: handleSubmit, })); }; const openDeleteModal = () => { setModal(prev=>({ ...prev, open: true, title: "Are you sure to delete", description: "now you are deleting", handleSubmit: handleDelete, })); }; return ( <Box sx={{ display: "flex", flexDirection: "column", p: 4, }} > <Box> Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo, aliquid? </Box> <Box> {text} </Box> <Modal title={modal?.title} description={modal?.description} open={modal?.open} handleSubmit={modal?.handleSubmit} text={text} onTextChange={(e) => setText(e.target.value)} handleClose={()=>setModal(defaultModal)} /> <Box> <ButtonGroup variant="contained" aria-label="outlined primary button group" > <Button onClick={openSubmitModal}>submit</Button> <Button onClick={openDeleteModal}>delete</Button> </ButtonGroup> </Box> </Box> ); }; export default Parent;
Modal组件
export default function Modal({open,title,description,handleSubmit,handleClose,text,onTextChange}) { return ( <Dialog open={open} onClose={handleClose} PaperProps={{ component: 'form', onSubmit: (event) => { event.preventDefault(); handleSubmit(); }, }} > <DialogTitle>{title}</DialogTitle> <DialogContent> <DialogContentText> {description} </DialogContentText> <TextField autoFocus required margin="dense" label="Comments" type="text" value={text} onChange={onTextChange} fullWidth variant="standard" /> </DialogContent> <DialogActions> <Button onClick={handleClose}>Cancel</Button> <Button type="submit">Submit</Button> </DialogActions> </Dialog> ); }
问题原因
当调用openSubmitModal或openDeleteModal时,会将当前的handleSubmit/handleDelete函数存入modal状态。由于闭包特性,这些函数捕获的是当时的text值(初始为空或之前的旧值)。后续用户输入更新text后,存入modal状态的函数依然引用旧的text值,导致提交时打印的不是最新输入内容。
解决方案
方案1:提交时传递最新的text值
修改Modal组件的表单提交逻辑,将当前的text作为参数传给handleSubmit:
// Modal组件中修改PaperProps的onSubmit PaperProps={{ component: 'form', onSubmit: (event) => { event.preventDefault(); handleSubmit(text); // 传递最新的text }, }}
然后修改父组件的处理函数,接收参数:
const handleSubmit = (currentText) => { console.log(currentText + " in submit"); setModal(defaultModal); }; const handleDelete = (currentText) => { console.log(currentText + " in delete"); setModal(defaultModal); };
方案2:不将处理函数存入modal状态,改用类型标识
在modal对象中添加type字段标记操作类型,父组件统一处理提交逻辑:
// 修改defaultModal const defaultModal = { open: false, title: "", description: "", type: "", // 添加type字段,可选值"submit"或"delete" }; // 修改openSubmitModal和openDeleteModal const openSubmitModal = () => { setModal(prev=>({ ...prev, open: true, title: "Are you sure to submit", description: "now you are submitting", type: "submit", })); }; const openDeleteModal = () => { setModal(prev=>({ ...prev, open: true, title: "Are you sure to delete", description: "now you are deleting", type: "delete", })); }; // 新增统一的提交处理函数 const handleModalSubmit = () => { if (modal.type === "submit") { console.log(text + " in submit"); } else if (modal.type === "delete") { console.log(text + " in delete"); } setModal(defaultModal); }; // 传递给Modal的handleSubmit改为handleModalSubmit <Modal // ...其他props handleSubmit={handleModalSubmit} // ...其他props />
方案3:使用useRef保存最新的text值
用useRef实时同步text的最新值,处理函数从ref中读取:
const Parent = () => { const [modal, setModal] = useState(defaultModal); const [text, setText] = useState(""); const textRef = useRef(""); // 同步text到ref useEffect(() => { textRef.current = text; }, [text]); const handleSubmit = () => { console.log(textRef.current + " in submit"); // 从ref读取最新值 setModal(defaultModal); }; const handleDelete = () => { console.log(textRef.current + " in delete"); setModal(defaultModal); }; // ...其余代码不变 };
以上三种方案都能解决提交时无法获取最新text值的问题,其中方案1和方案2更符合React的状态管理逻辑,推荐优先使用。
内容的提问来源于stack exchange,提问作者somnath navale
相关产品推荐
相关产品推荐

