Formik动态表单初始值无法读取,表单无法回显数据求助
Formik动态表单初始值无法回显问题解决
问题情况
使用Formik构建动态表单,初始值由generateInitialValues函数生成:无数据时返回空结构对象,存在历史数据时返回填充数据的同结构对象。但表单无法回显已有数据,测试发现:
- 打印
formik.values能看到带值的对象,字段的key也正确 - 通过
formik.values['Ticket' + formNumber + '.Field' + data.ticketDetailForm[i].id]读取时返回undefined - 手动输入字段内容后,Formik更新值,此时能正常读取对应值
- 已设置
enableReinitialize: true,表单提交可正常保存数据,仅初始值读取有问题
问题根源
- 初始值key与表单字段key不匹配:生成空初始值时,Field的key用了循环索引
j+1,但表单字段的key用的是data.ticketDetailForm[i].id,如果id不是连续的1、2、3,会导致两者key不对应。 - 嵌套对象访问方式错误:初始值是嵌套结构(
{ Ticket1: { FieldX: "" } }),但代码中用扁平的点连接字符串(如"Ticket1.FieldX")作为key访问formik.values,而Formik的嵌套结构需要用formik.values.Ticket1.FieldX或formik.values["Ticket1"]["FieldX"]的方式访问。
修复方案
1. 修正初始值生成逻辑
将generateInitialValues中Field的key从j+1改为data.ticketDetailForm[j].id,确保和表单字段的key完全对应:
function generateInitialValues(formData) { if(!formData.ticketDetails){ let object = {}; for (let i = 0; i < nrOfTickets; i++){ object["Ticket" + (i+1)] = {}; for (let j = 0; j < data.ticketDetailForm.length; j++){ // 用data.ticketDetailForm[j].id作为Field的key,而非循环索引 object["Ticket" + (i+1)]["Field" + data.ticketDetailForm[j].id] = ""; } } return object; } else { return formData.ticketDetails; } }
2. 修正formik.values的访问方式
在GenerateFields中,将扁平key访问改为嵌套对象访问,同时添加可选链避免对象不存在时抛出错误:
// 原错误写法 formik.values['Ticket' + formNumber + '.Field' + data.ticketDetailForm[i].id] // 修正为嵌套访问 formik.values['Ticket' + formNumber]?.['Field' + data.ticketDetailForm[i].id]
3. 确保字段name的正确性
表单input的name属性保持不变("Ticket" + formNumber + ".Field" + data.ticketDetailForm[i].id),Formik会自动将点分隔的name解析为嵌套路径,匹配初始值的结构。
完整修正代码
export default function TicketDetails({formData, editFormData}) { const initialObject = generateInitialValues(formData); const formik = useFormik({ enableReinitialize: true, initialValues: initialObject, onSubmit: values => { editFormData({ticketDetails: values}); }, }); return ( <form id="ticketDetails" onSubmit={formik.handleSubmit}> <GenerateCards formik={formik} /> <div className='h-6'></div> </form> ); } function GenerateCards({formik}){ let output = []; for (let i = 0; i < nrOfTickets; i++){ output.push( <div key={i} className="divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow mt-6"> <div className="px-4 py-5 sm:px-6"> <h3 className="text-lg font-semibold leading-6 text-gray-900">Ticket #{i+1}</h3> </div> <div className="px-4 py-5 sm:p-6 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2 lg:gap-4"> <GenerateFields formNumber={i+1} formik={formik}/> </div> </div> ); }; return output; } function GenerateFields({formNumber, formik}) { let fields = []; for (let i = 0; i < data.ticketDetailForm.length; i++){ const ticketKey = `Ticket${formNumber}`; const fieldKey = `Field${data.ticketDetailForm[i].id}`; const fieldValue = formik.values[ticketKey]?.[fieldKey]; console.log(formik.values); console.log(`${ticketKey}.${fieldKey}`); console.log(fieldValue); fields.push( <div key={i}> <label className="block text-sm font-medium leading-6 text-gray-900 pl-0.5 pb-1">{data.ticketDetailForm[i].label}</label> <input name={`${ticketKey}.${fieldKey}`} value={fieldValue || ""} onChange={formik.handleChange} type={data.ticketDetailForm[i].type} className="mb-4 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" placeholder={data.ticketDetailForm[i].placeholder} /> </div> ); } return fields; } function generateInitialValues(formData) { if(!formData.ticketDetails){ let object = {}; for (let i = 0; i < nrOfTickets; i++){ const ticketKey = `Ticket${i+1}`; object[ticketKey] = {}; for (let j = 0; j < data.ticketDetailForm.length; j++){ const fieldKey = `Field${data.ticketDetailForm[j].id}`; object[ticketKey][fieldKey] = ""; } } return object; } else { return formData.ticketDetails; } }
内容的提问来源于stack exchange,提问作者Pieter Pienaar
相关产品推荐
相关产品推荐

