You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义InputCode组件onValueSet回调中调用focus方法失效问题

问题原因

  1. 浏览器按键事件的默认行为冲突:onKeyPress事件触发时,浏览器默认会将焦点绑定在当前触发输入的输入框上,你在onKeyPress的同步流程中手动切换焦点后,后续的浏览器默认行为会把焦点重新拉回当前输入框,导致聚焦失效。而onKeyDown的触发时机早于浏览器的焦点绑定逻辑,所以相同逻辑放在onKeyDown中可以正常执行。
  2. React批量更新机制的影响:你在onKeyPress中同时触发了InputCode内部的状态更新setValueState和react-hook-form的表单状态更新,React18+会对事件回调中的所有状态更新做批量合并,等整个事件回调执行完成后才会重渲染DOM,你同步调用focus()时DOM可能还未完成最新状态的挂载,也会导致聚焦失效。

解决方法

方法1:将聚焦逻辑推迟到宏任务队列执行

用setTimeout把聚焦逻辑包装,等当前所有同步任务(包括React重渲染、浏览器默认事件行为)执行完成后再运行,修改handleOnValueSet即可:

const handleOnValueSet = (index: number) => {
  const formvalues = getValues();
  onCodeChange(formvalues);

  if (index + 1 < CODE_INPUTS.length) {
    setTimeout(() => {
      inputListRefs.current[index + 1].current?.focus();
    }, 0)
  }
}

方法2:阻止onKeyPress的默认行为

在InputCode的handleKeyPress中,确认输入是有效数字后,调用event.preventDefault()阻止浏览器默认的焦点保持行为:

const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
  const value: number = parseInt(event.key, 10);

  if (!isNaN(value)) {
    event.preventDefault(); // 新增该行阻止默认行为
    const valueString: string = value.toString();
    setValueState(valueString);
    onChange(valueString);
    onValueSet(valueString);
  }
};

方法3:通过useEffect监听值变化触发聚焦

单独监听表单值的变化,值更新后自动触发下一个输入框的聚焦,完全和事件时序解耦:

useEffect(() => {
  const lastFilledIndex = CODE_INPUTS.findLastIndex(input => getValues(input.name)?.length > 0);
  if (lastFilledIndex > -1 && lastFilledIndex + 1 < CODE_INPUTS.length) {
    inputListRefs.current[lastFilledIndex + 1].current?.focus();
  }
}, [getValues()])

内容的提问来源于stack exchange,提问作者Steve Rogers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 23:39:00