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

如何在Final Form的Field Array中设置React Select初始选中值

问题描述

我使用带可排序容器的React Select组件,提取的值格式如下:

{
  "fruits": [
    {
       "id": 3,
       "value": "vanilla",
       "label": "Vanilla"
    },
    {
       "id": 1,
       "value": "chocolate",
       "label": "Chocolate"
    }
  ]
} 

常规Select组件可通过传入id设置初始值,但现在从后端获取选中id列表(如[1,3]),需要在Final Form的Field Array中实现对应选项(香草、巧克力)的选中,该如何操作?

解决方案

要实现从后端id列表初始化Field Array中的React Select选中状态,需完成以下步骤:

1. 转换后端id列表为Final Form兼容的结构

后端返回的[1,3]是纯id数组,需要将其映射为Final Form能识别的格式——每个数组项对应包含fruittName的对象,且fruittName要匹配React Select的完整选项结构(包含id、value、label)。

编写转换函数:

// 后端返回的选中id列表
const selectedIds = [1, 3];

// 根据选项列表和选中id生成初始值
const generateInitialFruits = (ids) => {
  return ids.map(id => {
    const option = options.find(opt => opt.id === id);
    return {
      fruittName: option // 直接使用完整的选项对象
    };
  });
};

2. 适配React Select与Final Form的交互逻辑

React Select的value和onChange逻辑与原生input不同,需要手动适配Final Form的input props:

  • value:需传入完整的选项对象,而非单独的id
  • onChange:需将选中的完整选项对象传给Final Form的input.onChange

修改SortableItem中的Select组件:

<Field name={`${name}.fruittName`}>
  {({ input }) => (
    <Select
      options={options}
      placeholder="Select Flavor"
      // 匹配当前选中的选项对象
      value={options.find(opt => opt.id === input.value?.id) || null}
      // 将选中的完整选项对象同步到Final Form
      onChange={(selectedOption) => input.onChange(selectedOption)}
    />
  )}
</Field>

3. 设置正确的初始值

用转换函数生成的数组替换原initialValues.fruits:

const initialValues = {
  company: 'nagween',
  fruits: generateInitialFruits(selectedIds)
};
修改后的完整代码
import React from "react";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import arrayMutators from "final-form-arrays";
import { FieldArray } from "react-final-form-arrays";
import {
  SortableContainer,
  SortableElement,
  SortableHandle,
} from "react-sortable-hoc";
import Select from "react-select";

const options = [
  { id: 1, value: "chocolate", label: "Chocolate" },
  { id:2, value: "strawberry", label: "Strawberry" },
  { id:3, value: "vanilla", label: "Vanilla" },
];

// 后端返回的选中id列表
const selectedIds = [1, 3];

// 生成符合Final Form结构的初始水果数组
const generateInitialFruits = (ids) => {
  return ids.map(id => {
    const option = options.find(opt => opt.id === id);
    return {
      fruittName: option || {}
    };
  });
};

const DragHandle = SortableHandle(() => (
  <span style={{ cursor: "move" }}>Drag</span>
));

const SortableItem = SortableElement(({ name, fields, value }) => (
  <li>
    <DragHandle />
    <Field name={`${name}.fruittName`}>
      {({ input }) => (
        <Select
          options={options}
          placeholder="Select Flavor"
          // 匹配当前选中的选项对象
          value={options.find(opt => opt.id === input.value?.id) || null}
          // 将选中的完整选项对象传给Final Form
          onChange={(selectedOption) => input.onChange(selectedOption)}
        />
      )}
    </Field>
    <span onClick={() => fields.remove(value)} style={{ cursor: "pointer", marginLeft: "10px" }}>
      Remove
    </span>
  </li>
));

const SortableList = SortableContainer(({ items }) => {
  return (
    <ul style={{ listStyle: "none", padding: 0 }}>
      {items.map((name, index) => (
        <SortableItem
          key={`item-${index}`}
          index={index}
          value={index}
          name={name}
          fields={items}
        />
      ))}
    </ul>
  );
});

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const initialValues = {
  company: 'nagween',
  fruits: generateInitialFruits(selectedIds)
};

const onSubmit = async (values) => {
  console.log('values :>> ', values);
  await sleep(300);
  window.alert(JSON.stringify(values, 0, 2));
};

const sortEnd =
  (move) =>
  ({ oldIndex, newIndex }) => {
    move(oldIndex, newIndex);
  };


const Home = () => {
  return (
    <div>
      <Styles>
        <h1>React Final Form - Array Fields</h1>
        <Form
          initialValues={initialValues}
          onSubmit={onSubmit}
          mutators={{
            ...arrayMutators,
          }}
          render={({
            handleSubmit,
            form: {
              mutators: { push, pop },
            },
            pristine,
            reset,
            submitting,
            values,
          }) => {
            return (
              <form onSubmit={handleSubmit}>
                <div style={{ marginBottom: "15px" }}>
                  <label style={{ display: "block", marginBottom: "5px" }}>Company</label>
                  <Field name="company" component="input" />
                </div>

                <div className="buttons" style={{ marginBottom: "15px" }}>
                  <button
                    type="button"
                    onClick={() => push("fruits", { fruittName: null })}
                    style={{ marginRight: "10px" }}
                  >
                    Add Flavor
                  </button>
                  <button type="button" onClick={() => pop("fruits")}>
                    Remove Last Flavor
                  </button>
                </div>
                <FieldArray name="fruits">
                  {({ fields }) => (
                    <SortableList
                      useDragHandle={true}
                      items={fields}
                      onSortEnd={sortEnd(fields.move)}
                    />
                  )}
                </FieldArray> 
                <div className="buttons" style={{ marginTop: "15px" }}>
                  <button type="submit" disabled={submitting || pristine} style={{ marginRight: "10px" }}>
                    Submit
                  </button>
                  <button
                    type="button"
                    onClick={reset}
                    disabled={submitting || pristine}
                  >
                    Reset
                  </button>
                </div>
                <pre style={{ marginTop: "20px" }}>{JSON.stringify(values, 0, 2)}</pre>
              </form>
            );
          }}
        />
      </Styles>
    </div>
  );
};

export default Home;

内容的提问来源于stack exchange,提问作者Nagween Jaffer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:55:45