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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:15:32