React表单提交按钮加载态实现及弹窗关闭文本闪现问题咨询
问题原因
你使用的Material UI Dialog 组件默认带有退出过渡动画,调用close()后弹窗不会立刻从DOM中移除,会保留数百毫秒执行关闭动画。你当前的代码逻辑是close()执行后马上同步调用setLoading(false),状态更新早于动画结束,就会出现按钮文本短暂重现的问题。
解决方案
推荐通过监听弹窗打开状态重置loading,避免在关闭动画过程中修改按钮状态:
- 新增useEffect监听弹窗
open属性,每次弹窗打开时自动重置loading为false - 移除请求成功回调中的
setLoading(false)逻辑,保证关闭动画期间按钮始终保持加载状态
修改后的核心代码如下:
export const NewClientDialog = (props: INewClientDialogProps) => { const {open, close} = props; const [fn, setFn] = useState(""); const [ln, setLn] = useState(""); const [email, setEmail] = useState(""); const [pn, setPn] = useState(""); const [newUser, setNewUser] = useState<INewClientProps>(); const [loading, setLoading] = useState(false); // 每次弹窗打开时重置loading状态 useEffect(() => { if (open) { setLoading(false); } }, [open]); useEffect(() => { const newClient: INewClientProps = { firstName: fn, lastName: ln, email: email, phoneNumber: pn } setNewUser(newClient) }, [fn, ln, email, pn]) const onAddClient = () => { setLoading(true) createNewClient(newUser) .then(() => close()) // 移除原来的setLoading(false)逻辑 } const AddClientButton = () => { const contents = loading ? <CircularProgress /> : <div>Create new client</div> return ( <Button onClick={() => onAddClient()}> {contents} </Button> ); } return ( <div> <Dialog onClose={close} open={open}> <TextField label="First name" onChange={(value) => setFn(value.target.value)}/> <TextField label="Last name" onChange={(value) => setLn(value.target.value)}/> <TextField label="Email address" onChange={(value) => setEmail(value.target.value)}/> <TextField label="Phone number" onChange={(value) => setPn(value.target.value)}/> <AddClientButton /> </Dialog> </div> ) }
备选方案
你也可以用Dialog组件自带的onExited回调实现同样效果,该回调会在弹窗关闭动画完全结束、组件从DOM中移除后触发:
<Dialog onClose={close} open={open} onExited={() => setLoading(false)} >
内容的提问来源于stack exchange,提问作者Nimrod Sadeh
相关产品推荐
相关产品推荐

