id: fieldarray title:

custom_edit_url: https://github.com/jaredpalmer/formik/edit/master/docs/api/fieldarray.md

<FieldArray />是一个有助于常见数组/列表操作的组件。你传了一个name具有密钥路径的属性values持有相关数组。<FieldArray />然后,您将通过渲染道具访问数组助手方法。为方便起见,调用这些方法将触发验证并进行管理touched为了你。

  1. import React from 'react';
  2. import {Formik, Form, Field, FieldArray} from 'formik';
  3. // Here is an example of a form with an editable list.
  4. // Next to each input are buttons for insert and remove.
  5. // If the list is empty, there is a button to add an item.
  6. export const FriendList = () => (
  7. <div>
  8. <h1>Friend List</h1>
  9. <Formik
  10. initialValues={{friends: ['jared', 'ian', 'brent']}}
  11. onSubmit={values =>
  12. setTimeout(() => {
  13. alert(JSON.stringify(values, null, 2));
  14. }, 500)
  15. }
  16. render={({values}) => (
  17. <Form>
  18. <FieldArray
  19. name="friends"
  20. render={arrayHelpers => (
  21. <div>
  22. {values.friends && values.friends.length > 0 ? (
  23. values.friends.map((friend, index) => (
  24. <div key={index}>
  25. <Field name={`friends.${index}`} />
  26. <button
  27. type="button"
  28. onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
  29. >
  30. -
  31. </button>
  32. <button
  33. type="button"
  34. onClick={() => arrayHelpers.insert(index, '')} // insert an empty string at a position
  35. >
  36. +
  37. </button>
  38. </div>
  39. ))
  40. ) : (
  41. <button type="button" onClick={() => arrayHelpers.push('')}>
  42. {/* show this when user has removed all friends from the list */}
  43. Add a friend
  44. </button>
  45. )}
  46. <div>
  47. <button type="submit">Submit</button>
  48. </div>
  49. </div>
  50. )}
  51. />
  52. </Form>
  53. )}
  54. />
  55. </div>
  56. );

name: string

相关密钥的名称或路径values

validateOnChange?: boolean

默认是true。确定是否应该运行表单验证任何数组操作。

FieldArray 对象数组

您还可以按照约定迭代对象数组object[index]property要么object.index.property对于名称属性<Field />要么<input />中的元素<FieldArray />

  1. <Form>
  2. <FieldArray
  3. name="friends"
  4. render={arrayHelpers => (
  5. <div>
  6. {values.friends.map((friend, index) => (
  7. <div key={index}>
  8. <Field name={`friends[${index}].name`} />
  9. <Field name={`friends.${index}.age`} /> // both these conventions do
  10. the same
  11. <button type="button" onClick={() => arrayHelpers.remove(index)}>
  12. -
  13. </button>
  14. </div>
  15. ))}
  16. <button
  17. type="button"
  18. onClick={() => arrayHelpers.push({name: '', age: ''})}
  19. >
  20. +
  21. </button>
  22. </div>
  23. )}
  24. />
  25. </Form>

FieldArray 验证问题

验证可能很棘手<FieldArray>

如果你使用validationSchema并且您的表单具有数组验证要求(如最小长度)以及嵌套数组字段要求,显示错误可能会非常棘手。Formik / Yup 将在内部显示验证错误。例如,

  1. const schema = Yup.object().shape({
  2. friends: Yup.array()
  3. .of(
  4. Yup.object().shape({
  5. name: Yup.string()
  6. .min(4, 'too short')
  7. .required('Required'), // these constraints take precedence
  8. salary: Yup.string()
  9. .min(3, 'cmon')
  10. .required('Required') // these constraints take precedence
  11. })
  12. )
  13. .required('Must have friends') // these constraints are shown if and only if inner constraints are satisfied
  14. .min(3, 'Minimum of 3 friends')
  15. });

由于 Yup 和您的自定义验证函数应始终将错误消息作为字符串输出,因此您需要在显示它时嗅探嵌套错误是数组还是字符串。

所以…要显示'Must have friends''Minimum of 3 friends'(我们的示例的数组验证约束)…

  1. // within a `FieldArray`'s render
  2. const FriendArrayErrors = errors =>
  3. errors.friends ? <div>{errors.friends}</div> : null; // app will crash

  1. // within a `FieldArray`'s render
  2. const FriendArrayErrors = errors =>
  3. typeof errors.friends === 'string' ? <div>{errors.friends}</div> : null;

对于嵌套字段错误,您应该假定除非您已检查过,否则不会定义对象的任何部分。因此,你可能想帮自己一个忙,做一个习惯<ErrorMessage />看起来像这样的组件:

  1. import {Field, getIn} from 'formik';
  2. const ErrorMessage = ({name}) => (
  3. <Field
  4. name={name}
  5. render={({form}) => {
  6. const error = getIn(form.errors, name);
  7. const touch = getIn(form.touched, name);
  8. return touch && error ? error : null;
  9. }}
  10. />
  11. );
  12. // Usage
  13. <ErrorMessage name="friends[0].name" />; // => null, 'too short', or 'required'

注意:在 Formik v0.12 / 1.0 中,一个新的meta可以添加道具FieldFieldArray这将为您提供相关的元数据,如errortouch,这将使您免于必须使用 Formik 或 lodash 的 getIn 或检查路径是否由您自己定义。

FieldArray 助手

通过渲染道具可以使用以下方法。

  • push: (obj: any) => void:将值添加到数组的末尾
  • swap: (indexA: number, indexB: number) => void:在数组中交换两个值
  • move: (from: number, to: number) => void:将数组中的元素移动到另一个索引
  • insert: (index: number, value: any) => void:将给定索引处的元素插入到数组中
  • unshift: (value: any) => number:将一个元素添加到数组的开头并返回其长度
  • remove<T>(index: number): T | undefined:删除数组索引处的元素并将其返回
  • pop<T>(): T | undefined:从数组末尾删除并返回值
  • replace: (index: number, value: any) => void:将给定索引处的值替换为数组

FieldArray 渲染方法

有三种方法可以渲染<FieldArray />

  • <FieldArray name="..." component>
  • <FieldArray name="..." render>
  • <FieldArray name="..." children>

render: (arrayHelpers: ArrayHelpers) => React.ReactNode

  1. import React from 'react';
  2. import { Formik, Form, Field, FieldArray } from 'formik'
  3. export const FriendList = () => (
  4. <div>
  5. <h1>Friend List</h1>
  6. <Formik
  7. initialValues={{ friends: ['jared', 'ian', 'brent'] }}
  8. onSubmit={...}
  9. render={formikProps => (
  10. <FieldArray
  11. name="friends"
  12. render={({ move, swap, push, insert, unshift, pop }) => (
  13. <Form>
  14. {/*... use these however you want */}
  15. </Form>
  16. )}
  17. />
  18. />
  19. </div>
  20. );

component: React.ReactNode

  1. import React from 'react';
  2. import { Formik, Form, Field, FieldArray } from 'formik'
  3. export const FriendList = () => (
  4. <div>
  5. <h1>Friend List</h1>
  6. <Formik
  7. initialValues={{ friends: ['jared', 'ian', 'brent'] }}
  8. onSubmit={...}
  9. render={formikProps => (
  10. <FieldArray
  11. name="friends"
  12. component={MyDynamicForm}
  13. />
  14. )}
  15. />
  16. </div>
  17. );
  18. // In addition to the array helpers, Formik state and helpers
  19. // (values, touched, setXXX, etc) are provided through a `form`
  20. // prop
  21. export const MyDynamicForm = ({
  22. move, swap, push, insert, unshift, pop, form
  23. }) => (
  24. <Form>
  25. {/** whatever you need to do */}
  26. </Form>
  27. );

children: func

  1. import React from 'react';
  2. import { Formik, Form, Field, FieldArray } from 'formik'
  3. export const FriendList = () => (
  4. <div>
  5. <h1>Friend List</h1>
  6. <Formik
  7. initialValues={{ friends: ['jared', 'ian', 'brent'] }}
  8. onSubmit={...}
  9. render={formikProps => (
  10. <FieldArray name="friends">
  11. {({ move, swap, push, insert, unshift, pop, form }) => {
  12. return (
  13. <Form>
  14. {/*... use these however you want */}
  15. </Form>
  16. );
  17. }}
  18. <FieldArray/>
  19. )}
  20. />
  21. </div>
  22. );