如何在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:需传入完整的选项对象,而非单独的idonChange:需将选中的完整选项对象传给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
相关产品推荐
相关产品推荐

