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

