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

React中动态添加输入框后的焦点定位异常问题

问题分析

你遇到的问题核心是React的setState是异步更新:调用setValues([...values, ''])后,组件并不会立刻重新渲染DOM,此时你通过divRef.current获取到的还是更新前的DOM结构,所以querySelector('.child:last-child input')拿到的是原来的最后一个输入框(也就是新添加后变成倒数第二个的那个)。

解决方案

方法1:用useEffect监听values变化(推荐)

利用useEffect的依赖特性,当values数组更新完成、组件重新渲染后,再去获取最新的DOM元素并设置焦点:

import { useState, useRef, useEffect } from 'react';

export default function App() {
  const [values, setValues] = useState(['']);
  const divRef = useRef(null);

  const addInput = () => {
    setValues([...values, '']);
  };

  // 监听values变化,DOM更新后聚焦新输入框
  useEffect(() => {
    const lastInput = divRef.current?.querySelector('.child:last-child input');
    if (lastInput) {
      lastInput.focus();
    }
  }, [values]);

  return (
    <>
      <div ref={divRef}>
        {values.map((v, id) => (
          <div className="child" key={id}>
            <input onChange={() => {}} value={v} />
          </div>
        ))}
      </div>
      <button onClick={addInput}>Add</button>
    </>
  );
}

方法2:使用setState的回调+requestAnimationFrame

如果不想用useEffect,也可以利用setState的回调函数确保拿到最新的values,再用requestAnimationFrame等待DOM更新完成:

const addInput = () => {
  setValues(prevValues => [...prevValues, ''], () => {
    requestAnimationFrame(() => {
      const lastInput = divRef.current?.querySelector('.child:last-child input');
      if (lastInput) {
        lastInput.focus();
      }
    });
  });
};

额外优化提示

你当前用数组索引id作为元素的key,在列表项仅追加的场景下没问题,但如果后续涉及删除、排序等操作,可能会导致React的DOM复用逻辑出错,建议给每个输入框项生成唯一标识(比如UUID)作为key。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:25:30