Formik FieldArray更新排序后输入框焦点错位问题求助
Formik FieldArray排序后保持输入框焦点的解决方案
你当前的场景是:使用Formik的FieldArray组件管理带position字段的对象数组,渲染时按position排序,更新某一项的position后数组重新排序,但焦点会跳转到第一个输入框,而非用户刚编辑的项。要解决这个问题,核心是用唯一标识跟踪当前编辑的项,排序后重新定位焦点,具体步骤如下:
1. 给数组项添加唯一ID
因为position字段会动态修改,不能作为唯一标识,所以需要给每个对象添加一个不会重复的id字段。新增项时生成唯一ID:
push({ id: Date.now(), name: '', position: 0 });
2. 跟踪当前聚焦的项ID
用React的useState保存当前获得焦点的项的id:
const [focusedItemId, setFocusedItemId] = useState(null);
3. 绑定输入框的焦点事件
在position对应的输入框上添加onFocus事件,记录当前聚焦的项ID:
<Field name={`my_values[${index}].position`} onFocus={() => setFocusedItemId(value.id)} />
4. 排序后自动聚焦目标输入框
使用useEffect监听Formik的values变化,当focusedItemId存在时,找到对应项的输入框并调用focus方法:
useEffect(() => { if (focusedItemId) { const targetIndex = sortedValues.findIndex(item => item.id === focusedItemId); const inputElement = document.querySelector(`input[name="my_values[${targetIndex}].position"]`); inputElement?.focus(); } }, [sortedValues, focusedItemId]);
完整示例代码
import { Formik, Form, Field, FieldArray } from 'formik'; import { useState, useEffect } from 'react'; const MyForm = () => { const [focusedItemId, setFocusedItemId] = useState(null); return ( <Formik initialValues={{ my_values: [ { id: 1, name: 'Jane', position: 2 }, { id: 2, name: 'John', position: 1 } ] }} onSubmit={(values) => console.log(values)} > {({ values }) => { // 排序前先复制数组,避免直接修改原values const sortedValues = values.my_values.slice().sort((a, b) => a.position - b.position); // 监听排序后数组变化,重新聚焦目标输入框 useEffect(() => { if (focusedItemId) { const targetIndex = sortedValues.findIndex(item => item.id === focusedItemId); const inputElement = document.querySelector(`input[name="my_values[${targetIndex}].position"]`); inputElement?.focus(); } }, [sortedValues, focusedItemId]); return ( <Form> <FieldArray name="my_values"> {({ push, remove }) => ( <div> {sortedValues.map((value, index) => ( <div key={value.id}> <Field name={`my_values[${index}].name`} placeholder="Name" /> <Field name={`my_values[${index}].position`} type="number" placeholder="Position" onFocus={() => setFocusedItemId(value.id)} /> <button type="button" onClick={() => remove(index)}>删除</button> </div> ))} <button type="button" onClick={() => push({ id: Date.now(), name: '', position: 0 })} > 添加项 </button> </div> )} </FieldArray> <button type="submit">提交</button> </Form> ); }} </Formik> ); }; export default MyForm;
关键说明
- 用
slice()复制原数组再排序,避免直接修改Formik的values导致意外问题 - 依赖项的唯一
id跟踪焦点,不受position排序变化影响 useEffect在数组排序后自动定位并聚焦目标输入框
内容的提问来源于stack exchange,提问作者Tom McEvoy
相关产品推荐
相关产品推荐

