输入框内容变更时失焦问题求助(附React+Formik代码)
问题根源分析
你遇到的焦点丢失问题,核心原因是直接通过DOM操作修改input的value(inputRef.current.value = ...),这种方式绕过了React的状态管理机制,会导致React重新评估输入框的DOM状态,进而丢失焦点。另外,组件中虽使用了useRef,但未以受控组件方式管理输入框值,反而用副作用直接篡改DOM,这是触发问题的关键。
解决方案
放弃直接操作DOM的方式,改用受控组件管理输入框状态,结合Formik的字段值处理格式化逻辑,既能保留输入掩码效果,又不会丢失焦点。具体步骤如下:
- 将输入框改为受控组件:给input添加
value属性,绑定格式化后的Formik字段值,让React接管状态管理 - 优化变更处理逻辑:在
handleChange中先处理原始输入,再同步到Formik,格式化逻辑仅在渲染时处理,不直接修改DOM - 修复光标位置(可选但重要):格式化后光标可能跳至输入框末尾,添加光标位置修复逻辑,提升用户体验
修正后的代码
export const Component = (props: any) => { const inputRef = React.useRef<HTMLInputElement>(null); // 格式化函数,按需求调整掩码规则 const formatInputValue = (value: string) => { if (!value) return ""; return value.replace(/^(.{3})(.{0,2})(.{0,2}).*$/, (_, $1, $2, $3) => { let result = $1; if ($2) result += " " + $2; if ($3) result += " " + $3; return result; }); }; const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => { const rawValue = event.target.value.replace(/[^0-9]/g, ""); // 同步原始纯数字值到Formik的Additional_JKSO字段 props.formik.setFieldValue("Additional_JKSO", rawValue); // 同步格式化后的值到key1字段 props.formik.setFieldValue("key1", formatInputValue(rawValue)); }; // 修复光标位置:避免格式化后光标跳至末尾 React.useLayoutEffect(() => { if (inputRef.current) { const input = inputRef.current; const cursorPosition = input.selectionStart; const originalValue = input.value; const formattedValue = formatInputValue(props.formik.values.key1); if (originalValue !== formattedValue && cursorPosition !== null) { let offset = 0; for (let i = 0; i < cursorPosition; i++) { if (formattedValue[i] === " " && originalValue[i] !== " ") { offset++; } } input.setSelectionRange(cursorPosition + offset, cursorPosition + offset); } } }, [props.formik.values.key1]); if (props.fieldSchema.fieldKey === "key1") { return ( <div className="flex"> <div className="text-box"> <input className="text-box__input" maxLength={9} onChange={handleChange} disabled={props.disabled} ref={inputRef} // 受控组件:绑定格式化后的值 value={formatInputValue(props.formik.values.key1)} /> </div> </div> ); } return null; };
关键说明
- 受控组件的优势:通过
value属性绑定状态,React会自动处理DOM更新,不会出现焦点丢失情况,因为React明确输入框状态是受控的,不会随意重置DOM - 避免直接DOM操作:原代码中
useLayoutEffect直接修改input的value是反模式,现在改为状态驱动渲染,副作用仅用于修复光标位置,不会触发DOM重置 - 字段同步:Formik的
key1存储格式化后的值,Additional_JKSO存储原始纯数字值,既满足展示需求,又不影响后续数据提交
内容的提问来源于stack exchange,提问作者NoOneCare
相关产品推荐
相关产品推荐

