React注册页面提交按钮无法禁用的问题排查
注册提交按钮无法禁用问题
问题现象
- 在按钮组件上设置
disabled={loading}属性不生效 - 尝试创建常量
isDisabled=true模拟禁用样式,但样式无法动态切换,点击提交时按钮仍不会变为禁用状态
原代码
import styles, {layout} from '../style'; import {eye, eye_hidden, google} from "../assets"; import {useState, useRef} from 'react'; import {useAuth} from '../contexts/AuthContext'; const SignUp = () => { const {signup, currentUser} = useAuth() const nameRef = useRef() const emailRef = useRef() const emailConfRef = useRef() const pwRef = useRef() const pwConfRef = useRef() const [error, setError] = useState("") const [loading, setLoading] = useState(false) const [visibility_pw, setVisibility_pw] = useState(false) const [visibility_pwConf, setVisibility_pwConf] = useState(false) const handleVisibility = param => event => { param === "pw" ? setVisibility_pw(!visibility_pw) : setVisibility_pwConf(!visibility_pwConf) } async function handleSubmit(event) { event.preventDefault() if (pwRef.current.value !== pwConfRef.current.value) { return setError('Passwords or Emails do not match. Please try again.') } if (emailRef.current.value !== emailConfRef.current.value) { return setError('Emails do not match!') } try { setError('') setLoading(true) signup(emailRef.current.value, pwRef.current.value) } catch(error) { console.log(error.message) setError('Unable to create account. Please try again') } setLoading(false) } return ( <div className={`${layout.sectionCenter} min-h-screen`}> <div className="bg-black/25 shadow-xl shadow-[#8F6E5D]/40 rounded-2xl p-5 min-h-full xs:w-full max-w-[800px]"> <h2 className={`text-center mt-8 ${styles.heading4}`}>Create A New Account</h2> {error && <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mx-8 mt-8" role="alert"> <strong className="block sm:inline font-bold">{error}</strong> </div>} {currentUser && currentUser.email} <form action="" onSubmit={handleSubmit} className="flex flex-col px-8 gap-8 mt-12"> <input required type="text" name="name" id="name" ref={nameRef} placeholder="Enter Full Name" className="pl-2 py-2.5 rounded-lg border border-[#8F6E5D] border-opacity-75 bg-primary text-secondary" /> <input required type="email" name="email" id="email" ref={emailRef} placeholder="Enter Email" className="pl-2 py-2.5 rounded-lg border border-[#8F6E5D] border-opacity-75 bg-primary text-secondary" /> <input required type="email" name="email_conf" id="email_conf" ref={emailConfRef} placeholder="Confirm Email" className="pl-2 py-2.5 rounded-lg border border-[#8F6E5D] border-opacity-75 bg-primary text-secondary" /> <div className="relative"> <input required type={visibility_pw ? "text" : "password"} name="password" id="password" ref={pwRef} placeholder="Enter Password" className="pl-2 py-2.5 rounded-lg border border-[#8F6E5D] border-opacity-75 bg-primary w-full text-secondary" /> <img onClick={handleVisibility("pw")} src={visibility_pw ? eye_hidden : eye} alt="toggle password visibility" className={`${visibility_pw ? "h-[20px]" : "h-[65%]"} pw_visibility absolute top-[50%] right-5 -translate-y-[50%] cursor-pointer`} /> </div> <div className="relative"> <input required type={visibility_pwConf ? "text" : "password"} name="password_conf" id="password_conf" ref={pwConfRef} placeholder="Confirm Password" className="pl-2 py-2.5 rounded-lg border border-[#8F6E5D] border-opacity-75 bg-primary w-full text-secondary" /> <img onClick={handleVisibility("pw_conf")} src={visibility_pwConf ? eye_hidden : eye} alt="toggle confirm password visibility" className={`${visibility_pwConf ? "h-[20px]" : "h-[65%]"} pw_visibility absolute top-[50%] right-5 -translate-y-[50%] cursor-pointer`} /> </div> <button disabled={loading} type="submit" className={`py-2 px-6 font-playfairDisplay font-medium text-[18px] outline-none rounded-lg ${loading ? "bg-gradient-to-r from-[#8F6E5D]/50 to-[#7E4F43]/50 text-dimWhite/50" : "bg-gradient-to-r from-[#8F6E5D] to-[#7E4F43] text-white"} ${loading ? "" : styles.buttonHover} mx-auto mt-4`}>Sign Up</button> </form> <div className="mt-12 grid grid-cols-3 px-8 items-center"> <hr className="opacity-25"/> <p className={`${styles.paragraph} text-center text-md`}>OR</p> <hr className="opacity-25"/> </div> <button type="button" className="bg-white border py-2 px-4 mt-8 mb-12 mx-auto rounded-lg flex justify-center items-center text-center hover:scale-95 duration-300"> <img src={google} alt="google icon" className="h-[32px] w-[32px]" /> <p className="ml-3">Sign up with Google</p> </button> <div className="flex justify-between px-8 mt-4 mb-8"> <p className={`${styles.paragraph} text-sm sm:text-lg`}>Have an account?</p> <button type="button" className="hover:scale-90 duration-300 hover:text-[#8F6E5D] hover:from-[#FAF6F5] hover:to-[#FAF6F5] hover:ease-in-out cursor-pointer py-1 px-2 bg-gradient-to-r from-[#8F6E5D] to-[#7E4F43] font-playfairDisplay font-medium text-[18px] text-white outline-none rounded-lg">Login</button> </div> </div> </div> ) } export default SignUp
尝试的修改代码
<button disabled={loading} type="submit" className={`py-2 px-6 font-playfairDisplay font-medium text-[18px] outline-none rounded-lg ${isDisabled ? "bg-gradient-to-r from-[#8F6E5D]/50 to-[#7E4F43]/50 text-dimWhite/50" : "bg-gradient-to-r from-[#8F6E5D] to-[#7E4F43] text-white"} ${isDisabled ? "" : styles.buttonHover} mx-auto mt-4`}>Sign Up</button>
解决方案
问题核心在于handleSubmit函数中,异步操作signup未等待完成就直接执行setLoading(false),导致loading状态刚设为true就立刻变回false,按钮无法保持禁用状态。同时,常量isDisabled的值不会随状态变化,无法实现动态样式切换。
修改handleSubmit函数,添加await等待signup完成,并将setLoading(false)放入finally块确保无论操作成功或失败都会执行:
async function handleSubmit(event) { event.preventDefault() if (pwRef.current.value !== pwConfRef.current.value) { return setError('Passwords or Emails do not match. Please try again.') } if (emailRef.current.value !== emailConfRef.current.value) { return setError('Emails do not match!') } try { setError('') setLoading(true) await signup(emailRef.current.value, pwRef.current.value) // 等待异步注册完成 } catch(error) { console.log(error.message) setError('Unable to create account. Please try again') } finally { setLoading(false) // 无论成功失败都重置loading状态 } }
同时保持按钮的disabled={loading}和用loading状态控制样式的逻辑,无需使用常量isDisabled:
<button disabled={loading} type="submit" className={`py-2 px-6 font-playfairDisplay font-medium text-[18px] outline-none rounded-lg ${loading ? "bg-gradient-to-r from-[#8F6E5D]/50 to-[#7E4F43]/50 text-dimWhite/50" : "bg-gradient-to-r from-[#8F6E5D] to-[#7E4F43] text-white"} ${loading ? "" : styles.buttonHover} mx-auto mt-4`}>Sign Up</button>
修改后,点击提交按钮时loading变为true,按钮进入禁用状态并切换样式;等待注册操作完成后,loading变回false,按钮恢复可用状态。
内容的提问来源于stack exchange,提问作者Ramana
相关产品推荐
相关产品推荐

