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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:09:22