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
相关产品推荐
相关产品推荐

