React输入框触发onChange后如何保持焦点?
ReactTable输入框失焦问题解决指南
你遇到的输入框在输入时失焦,本质是React重渲染过程中,输入框对应的DOM节点被销毁后重建了——哪怕你把输入框抽离成独立组件,要是组件定义位置不对、key不稳定,或者触发了不必要的全量重渲染,照样会出问题。下面结合错误写法和修正后的代码,给你拆解核心解决要点:
错误写法示例(你可能踩的坑)
function MyTable() { const [data, setData] = useState([{ id: 1, value: '' }, { id: 2, value: '' }]); // 错误:在父组件内部定义子组件,每次重渲染都会生成全新的组件类型 const InputCell = ({ row }) => { const handleChange = (e) => { const newData = [...data]; newData[row.index].value = e.target.value; setData(newData); }; return <input value={row.original.value} onChange={handleChange} />; }; const columns = [ { Header: '输入列', Cell: ({ row }) => <InputCell row={row} /> } ]; return <ReactTable data={data} columns={columns} />; }
问题根源
InputCell定义在MyTable内部,每次MyTable因状态更新重渲染时,都会生成一个全新的InputCell组件类型。React会判定这是不同的组件,直接卸载旧的输入框DOM,再挂载新的,自然就失焦了。- 没有缓存
columns和handleChange,每次渲染都会生成新的引用,触发ReactTable全量重渲染。 - 未指定稳定的行key,默认用数组index当key,数据更新时可能导致行DOM复用错误。
修正后的代码
// 正确:把输入框组件定义在父组件外部,确保组件类型全局稳定 const InputCell = ({ value, onChange }) => { return <input value={value} onChange={onChange} />; }; function MyTable() { const [data, setData] = useState([{ id: 1, value: '' }, { id: 2, value: '' }]); // 用useCallback缓存回调函数,避免每次渲染生成新函数触发子组件重渲染 const handleInputChange = useCallback((id, e) => { setData(prevData => prevData.map(item => item.id === id ? { ...item, value: e.target.value } : item ) ); }, []); // 用useMemo缓存columns配置,避免引用变化触发ReactTable全量重渲染 const columns = useMemo(() => [ { Header: '输入列', Cell: ({ row }) => ( <InputCell value={row.original.value} onChange={(e) => handleInputChange(row.original.id, e)} /> ) } ], [handleInputChange]); // 指定稳定的行key,用数据自身的唯一id而非index return <ReactTable data={data} columns={columns} getRowId={(row) => row.id} />; }
核心解决要点
- 固定组件定义位置:将输入框组件放在父组件外部,确保组件类型在整个渲染周期中保持一致,React只会更新props,不会卸载重建DOM。
- 缓存依赖项:用
useMemo缓存columns数组,useCallback缓存输入变更的回调函数,避免因引用变化触发不必要的重渲染。 - 稳定的行key:通过
getRowId指定数据自身的唯一标识(比如id)作为行的key,不要用数组index——index会随数据顺序变化,导致React无法正确复用行DOM。 - 不可变状态更新:修改数据时用
map、扩展运算符等不可变方式,避免直接修改原数组,这不仅是React最佳实践,也能减少不必要的重渲染触发。
内容的提问来源于stack exchange,提问作者Andrew Kloos
相关产品推荐
相关产品推荐

