表单自动填充时为什么 input 值变了但 React 状态没更新?
我在用 React 做登录页,用户保存过账号密码后,浏览器自动填充用户名和密码,但发现 state 里还是空的。比如我用 useState 控制的 email 字段,虽然输入框显示了自动填充的值,但提交时拿到的 state 却是初始值。
我试过加 onChange 监听,但自动填充好像不会触发这个事件。网上有人说要用 useRef 配合 useEffect 手动读取,但具体怎么写不太确定,有没有靠谱的解决方案?
const [email, setEmail] = useState('');
const emailRef = useRef(null);
useEffect(() => {
const timer = setTimeout(() => {
if (emailRef.current?.value && !email) {
setEmail(emailRef.current.value);
}
}, 100);
return () => clearTimeout(timer);
}, [email]);
你那个 setTimeout 的写法虽然思路是对的(轮询检查),但时机特别难把握,100ms 可能浏览器还没填充完,或者填充完了但还没挂载到 DOM 上,很不稳,而且写定时器还要记得清理,代码也挺乱。
其实有个更简单、更靠谱的办法,就是把 onChange 换成 onInput。onInput 事件的触发机制更底层,大部分浏览器在自动填充的时候都会触发它,能完美解决这个问题。你可以试试把代码改成这样:
一般情况下,换成 onInput 就能解决 90% 的问题。如果你遇到那种特别顽固的浏览器(比如某些版本的 Safari 或者 Chrome 的奇怪行为),onInput 也不灵,那就不跟它较劲了。既然你已经在用 useRef,提交的时候直接读 DOM 的值就行了,别非得把 state 更新过来。
就像这样,提交时做个兜底:
这样不管是用户手动输的,还是浏览器自动填的,最后都能拿到正确的值,省得写一堆定时器还要担心内存泄漏,维护起来也轻松。