React中处理input和textarea的onFocus、onBlur事件时聚焦状态异常如何解决
问题根因
切换焦点时的事件触发顺序导致了状态空档:从textarea切换到input的过程中,textarea的onBlur会先执行,直接把contentFocused设为false,此时input的onFocus还没触发,两个状态同时为false,UI就会出现临时收缩的情况。
修复方案
方案1:最小改动修复原有逻辑
给失焦逻辑加短延时,预留出焦点切换的时间,避免误判状态:
import { useState, useRef } from 'react'; // 初始化状态改为布尔值false,更符合逻辑 const [titleFocused, setTitleFocus] = useState(false); const [contentFocused, setContentFocus] = useState(false); // 存储延时任务id const blurTimer = useRef(null); function handleFocus(event) { // 聚焦时先清空未执行的失焦任务,说明是表单内切换,不需要收缩 if (blurTimer.current) { clearTimeout(blurTimer.current); blurTimer.current = null; } const {name} = event.target; name === 'title' && setTitleFocus(true); name === 'content' && setContentFocus(true); } function handleUnfocus(event) { const {name} = event.target; // 延时100ms再修改状态,确认没有新的聚焦动作再收缩 blurTimer.current = setTimeout(() => { name === 'title' && setTitleFocus(false); name === 'content' && setContentFocus(false); }, 100); } return ( <div > <form className="create-note"> {/* 注意原逻辑缺少括号,运算符优先级可能导致判断错误,这里补加括号 */} {(titleFocused || contentFocused) && ( <input name="title" onChange={handleChange} value={note.title} placeholder="Title" onFocus={handleFocus} onBlur={handleUnfocus} /> )} <textarea name="content" onChange={handleChange} value={note.content} placeholder="Take a note..." onFocus={handleFocus} onBlur={handleUnfocus} rows={titleFocused || contentFocused ? "3" : "1"} /> <Zoom in={titleFocused || contentFocused} appear={true}> <Fab onClick={submitNote}> <AddIcon fontSize="large" /> </Fab> </Zoom> </form> </div> );
方案2:更简洁的全局表单状态方案
不需要维护两个独立的输入框聚焦状态,直接监听整个表单的聚焦/失焦事件即可:只有焦点完全离开表单时才触发收缩,表单内部切换焦点不会触发表单失焦,从根源避免了空档问题,代码也更精简:
import { useState } from 'react'; const [formFocused, setFormFocused] = useState(false); return ( <div > <form className="create-note" onFocus={() => setFormFocused(true)} onBlur={() => setFormFocused(false)} > {formFocused && ( <input name="title" onChange={handleChange} value={note.title} placeholder="Title" /> )} <textarea name="content" onChange={handleChange} value={note.content} placeholder="Take a note..." rows={formFocused ? "3" : "1"} /> <Zoom in={formFocused} appear={true}> <Fab onClick={submitNote}> <AddIcon fontSize="large" /> </Fab> </Zoom> </form> </div> );
内容的提问来源于stack exchange,提问作者Vladd Cantor
相关产品推荐
相关产品推荐

