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

React中高阶组件包裹受控表单元素导致聚焦丢失的解决方案咨询

React中高阶组件包裹受控表单元素导致聚焦丢失的解决方案咨询

嘿,我来帮你分析下这个问题~ 首先你的HOC写法本身没太大毛病,但导致焦点丢失的大概率是组件类型不稳定的问题,我给你拆解下原因和解决办法:

先找根因:为什么会丢焦点?

React判断组件是否需要卸载重挂载,是看组件的类型是否变化。如果你在某个组件的渲染逻辑(比如函数组件的函数体里)每次都调用withClearButton(Input)来创建增强组件,相当于每次渲染都生成一个全新的组件类型。React会把旧的组件完全卸载,再挂载新的——这时候输入框自然就丢焦点了。

解决方案1:固定增强组件的定义位置

把增强后的组件定义在组件外部,确保每次渲染都是同一个组件类型:

// 定义在组件外部,只执行一次
const ClearableInput = withClearButton(Input);

function MyForm() {
  const [value, setValue] = useState('');
  
  return (
    <ClearableInput 
      value={value} 
      onChange={(e) => setValue(e.target.value)} 
      onClearButtonClick={() => setValue('')}
    />
  );
}

如果确实需要在组件内部动态创建(比如根据不同条件增强不同组件),用useMemo缓存增强后的组件:

function MyForm() {
  const [value, setValue] = useState('');
  // 用useMemo缓存,避免每次渲染重新创建组件
  const ClearableInput = useMemo(() => withClearButton(Input), []);
  
  return <ClearableInput value={value} onChange={...} />;
}

解决方案2:改用组合模式替代HOC(更推荐)

HOC虽然能实现功能扩展,但嵌套多了会让组件树变复杂,而且容易出现这类组件稳定性问题。React更推荐用组合(Composition) 的方式来封装这类附加功能:

import { ComponentType } from 'react';
import styles from './ClearableInput.module.scss';
import { Button } from '../../../../Button/Button';
import { Icon } from '../../../../Icon/Icon';

type ClearableInputProps<BaseProps> = BaseProps & {
  component: ComponentType<BaseProps>;
  onClearButtonClick?: () => void;
};

export function ClearableInput<BaseProps>({
  component: Component,
  onClearButtonClick,
  ...restProps
}: ClearableInputProps<BaseProps>) {
  const handleClear = () => {
    onClearButtonClick?.();
  };

  return (
    <div className={styles.base}>
      <Component {...restProps as BaseProps} />
      <Button className={styles.button} onClick={handleClear} appearance="icon">
        <Icon icon={'ri-close-line'} />
      </Button>
    </div>
  );
}

// 使用的时候直接传基础组件作为props
function MyForm() {
  const [value, setValue] = useState('');
  
  return (
    <ClearableInput
      component={Input}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      onClearButtonClick={() => setValue('')}
    />
  );
}

这种方式更直观,组件结构清晰,也完全避免了HOC带来的组件类型不稳定问题,而且你不需要修改任何基础组件的代码。

额外排查点

  • 检查基础组件的实现:确保你的Input/Textarea组件是正确的受控组件,没有在内部维护独立的状态导致props更新时出现冲突。
  • 列表渲染时的key:如果是在列表里渲染这些输入组件,一定要给每个组件设置稳定且唯一的key,别用数组index当key,否则React也可能错误地卸载/挂载组件导致焦点丢失。

备注:内容来源于stack exchange,提问作者MFischer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 08:48:06