React嵌套输入组件在Android GBoard输入时出现内容重复问题
GBoard输入"@"时受控组件内容重复的问题
组件代码
const Child = ({ onChange, value }) => { const [localValue, setLocalValue] = useState(""); useEffect(() => { setLocalValue(value); }, [value]); return <input onChange={onChange} value={localValue} />; }; const Parent = () => { const [value, setValue] = useState(""); const handleChange = (e) => setValue(e.target.value); return <Child onChange={handleChange} value={value} />; };
组件说明
该子组件为受控输入组件,会先将父组件传入的value存入本地状态localValue,再将localValue绑定到输入框的value属性进行渲染。
问题现象
- 桌面Chrome环境下输入表现正常,内容可正常显示
- 使用Android GBoard(版本12.2.05.469624536-release-arm64-v8)输入时,输入"@"字符后内容会重复:例如输入"test"无异常,但输入"test@"会立即变为"testtest@",有时会变成"test@test@"
- 此问题仅在输入"@"后出现,且不会在其他安卓键盘上发生
能否复现?
能复现该问题,在指定场景与GBoard版本下可稳定触发。
原因解释
问题核心在于GBoard输入"@"的特殊事件逻辑,与子组件冗余的本地状态更新机制冲突:
- GBoard输入"@"时会触发两次
onChange事件:第一次传递插入"@"前的文本(如"test"),第二次传递插入"@"后的完整文本(如"test@") - 子组件通过
useEffect异步同步父组件value到本地localValue,当第一次onChange触发父状态更新后,useEffect还未执行,第二次onChange又触发父状态更新,导致两次useEffect的执行顺序与事件触发顺序出现错位 - 叠加GBoard对输入框值的重复读取逻辑,最终造成文本拼接重复;另外,子组件额外维护本地状态的设计本身违背了受控组件的原则,这是状态不同步的根源。
解决方案
移除子组件的本地状态,让输入框直接绑定父组件传入的value,回归标准受控组件实现:
const Child = ({ onChange, value }) => { return <input onChange={onChange} value={value} />; }; const Parent = () => { const [value, setValue] = useState(""); const handleChange = (e) => setValue(e.target.value); return <Child onChange={handleChange} value={value} />; };
该方案既符合React受控组件的设计规范,也从根源上避免了状态不同步导致的重复问题。
内容的提问来源于stack exchange,提问作者Edwin Tandiono
相关产品推荐
相关产品推荐

