React Formik FieldArray的push与remove方法失效问题排查
我想实现一个动态表单,参考教程用Formik的remove和push方法。现在浏览器能渲染所有数据,但点击“Delete”或“Add”按钮完全没反应,也没报错,不知道怎么调试修复。
另外,教程里作者用了values作为默认Props获取数据,我没这么做,会不会是问题根源?values的使用场景是什么?作者没解释。
附上代码:
function CreateTestSuite3() { const initialValues = { testSuite: { tsId: 0, tsName: "", tsDescription: "", testCases: [ { testCaseNumber: 0, testCaseName: "", testCaseEnvironment: "", testCaseSQL: "" } ] } }; const onSubmit = (data) => { console.log("this is form data: ", data); axios.post("http://localhost:8080/TestSuite/CreateTestSuite", data) .then((response) => { console.log("Form Submitted"); }) }; return ( <div className="CreateTestSuite"> <Formik initialValues={initialValues} onSubmit={onSubmit}> <Form className="formContainer"> <label>Test Suite Id: </label> <ErrorMessage name="tsId" component="span" /> <Field autoComplete="off" name="testSuite.tsId" placeholder="tsId" /> <label>Test Suite Name: </label> <ErrorMessage name="tsName" component="span" /> <Field autoComplete="off" name="testSuite.tsName" placeholder="tsName" /> <label>Test Suite Description: </label> <ErrorMessage name="tsDescription" component="span" /> <Field autoComplete="off" name="testSuite.tsDescription" placeholder="tsDescription" /> <FieldArray name="testSuite.testCases"> {({push, remove, }) => ( <> {initialValues.testSuite.testCases.map((TestCase, index) => ( <div key={index}> <label>Test Case Number: </label> <Field name={`TestCase.${index}.testCaseNumber`} placeholder="testCaseNumber" ></Field> <label>Test Case Name: </label> <Field name={`TestCase.${index}.testCaseName`} placeholder="testCaseName" ></Field> <label>Test Case Environment: </label> <Field name={`TestCase[${index}].testCaseEnvironment`} placeholder="testCaseEnvironment" ></Field> <label>Test Case SQL: </label> <Field name={`TestCase[${index}].testCaseSQL`} placeholder="testCaseSQL" ></Field> <button type="button" onClick={() => remove(index)} >Delete</button> </div> ))} <button type="button" onClick={() => push({ testCaseNumber: 0, testCaseName: "", testCaseEnvironment: "", testCaseSQL: "" })}>Add Test Case</button> </> )} </FieldArray> <button type="submit">Create Test Suite</button> </Form> </Formik> </div> ) }
你的代码有两个核心问题导致按钮无响应:
1. 遍历静态初始值而非Formik实时状态
你用initialValues.testSuite.testCases.map渲染列表,但initialValues是组件初始化时的静态数据,不会随Formik内部状态更新而变化。点击push/remove后Formik状态已经改变,但你仍在渲染旧的初始列表,所以看不到界面变化,且remove操作的索引也无法对应实时数据。
修复:从FieldArray的render props中获取form对象,用form.values.testSuite.testCases遍历:
<FieldArray name="testSuite.testCases"> {({ push, remove, form }) => ( <> {form.values.testSuite.testCases.map((testCase, index) => ( // 渲染列表项 ))} {/* Add按钮 */} </> )} </FieldArray>
2. Field的name属性路径错误
你写的TestCase.${index}.xxx或TestCase[${index}].xxx路径不正确,Formik中数组的实际路径是testSuite.testCases,正确的name应该是testSuite.testCases[${index}].testCaseNumber(或点语法testSuite.testCases.${index}.testCaseNumber)。路径错误会导致控件无法绑定到Formik状态,也会影响push/remove的有效性。
修复后的Field示例:
<Field name={`testSuite.testCases[${index}].testCaseNumber`} placeholder="testCaseNumber" />
完整修复后的FieldArray代码
<FieldArray name="testSuite.testCases"> {({ push, remove, form }) => ( <> {form.values.testSuite.testCases.map((testCase, index) => ( <div key={index}> <label>Test Case Number: </label> <Field name={`testSuite.testCases[${index}].testCaseNumber`} placeholder="testCaseNumber" /> <label>Test Case Name: </label> <Field name={`testSuite.testCases[${index}].testCaseName`} placeholder="testCaseName" /> <label>Test Case Environment: </label> <Field name={`testSuite.testCases[${index}].testCaseEnvironment`} placeholder="testCaseEnvironment" /> <label>Test Case SQL: </label> <Field name={`testSuite.testCases[${index}].testCaseSQL`} placeholder="testCaseSQL" /> <button type="button" onClick={() => remove(index)}>Delete</button> </div> ))} <button type="button" onClick={() => push({ testCaseNumber: 0, testCaseName: "", testCaseEnvironment: "", testCaseSQL: "" })}>Add Test Case</button> </> )} </FieldArray>
values的疑问 教程里的values是Formik当前的实时表单状态值,是Formik通过render props传递的核心数据:
- 使用场景:当你需要获取表单当前状态(比如遍历动态数组、根据表单值做条件渲染)时,必须用
values而非initialValues——因为initialValues仅在组件初始化时赋值一次,后续表单状态更新不会改变它。 - 你之前不用
values直接用initialValues,正是按钮点击后界面不更新的核心原因:你始终在渲染静态初始列表,没有同步Formik的实时状态。
内容的提问来源于stack exchange,提问作者Xander Kao

