| Formik">
<FieldArray />
是一个有助于常见数组/列表操作的组件。你向其传递一个 name
属性,其中包含 values
中保存相关数组的键的路径。然后,<FieldArray />
将允许你通过渲染属性访问数组辅助方法。为了方便起见,调用这些方法将触发验证并为你管理 touched
。
¥<FieldArray />
is a component that helps with common array/list manipulations. You pass it a name
property with the path to the key within values
that holds the relevant array. <FieldArray />
will then give you access to array helper methods via render props. For convenience, calling these methods will trigger validation and also manage touched
for you.
import React from 'react';import { Formik, Form, Field, FieldArray } from 'formik';// Here is an example of a form with an editable list.// Next to each input are buttons for insert and remove.// If the list is empty, there is a button to add an item.export const FriendList = () => (<div><h1>Friend List</h1><FormikinitialValues={{ friends: ['jared', 'ian', 'brent'] }}onSubmit={values =>setTimeout(() => {alert(JSON.stringify(values, null, 2));}, 500)}render={({ values }) => (<Form><FieldArrayname="friends"render={arrayHelpers => (<div>{values.friends && values.friends.length > 0 ? (values.friends.map((friend, index) => (<div key={index}><Field name={`friends.${index}`} /><buttontype="button"onClick={() => arrayHelpers.remove(index)} // remove a friend from the list>-</button><buttontype="button"onClick={() => arrayHelpers.insert(index, '')} // insert an empty string at a position>+</button></div>))) : (<button type="button" onClick={() => arrayHelpers.push('')}>{/* show this when user has removed all friends from the list */}Add a friend</button>)}<div><button type="submit">Submit</button></div></div>)}/></Form>)}/></div>);
name: string
values
中相关键的名称或路径。
¥The name or path to the relevant key in values
.
validateOnChange?: boolean
默认为 true
。确定在任何数组操作之后是否应该运行表单验证。
¥Default is true
. Determines if form validation should or should not be run after any array manipulations.
¥FieldArray Array of Objects
你还可以通过遵循 <FieldArray />
中 <Field />
或 <input />
元素的名称属性的 object[index].property
或 object.index.property
约定来迭代对象数组。
¥You can also iterate through an array of objects, by following a convention of object[index].property
or object.index.property
for the name attributes of <Field />
or <input />
elements in <FieldArray />
.
<Form><FieldArrayname="friends"render={arrayHelpers => (<div>{values.friends.map((friend, index) => (<div key={index}>{/** both these conventions do the same */}<Field name={`friends[${index}].name`} /><Field name={`friends.${index}.age`} /><button type="button" onClick={() => arrayHelpers.remove(index)}>-</button></div>))}<buttontype="button"onClick={() => arrayHelpers.push({ name: '', age: '' })}>+</button></div>)}/></Form>
¥FieldArray Validation Gotchas
使用 <FieldArray>
进行验证可能会很棘手。
¥Validation can be tricky with <FieldArray>
.
如果你使用 validationSchema
并且你的表单具有数组验证要求(例如最小长度)以及嵌套数组字段要求,则显示错误可能会很棘手。Formik/Yup 会从里到外显示验证错误。例如,
¥If you use validationSchema
and your form has array validation requirements (like a min length) as well as nested array field requirements, displaying errors can be tricky. Formik/Yup will show validation errors inside out. For example,
const schema = Yup.object().shape({friends: Yup.array().of(Yup.object().shape({name: Yup.string().min(4, 'too short').required('Required'), // these constraints take precedencesalary: Yup.string().min(3, 'cmon').required('Required'), // these constraints take precedence})).required('Must have friends') // these constraints are shown if and only if inner constraints are satisfied.min(3, 'Minimum of 3 friends'),});
由于是的,你的自定义验证函数应该始终将错误消息输出为字符串,因此当你要显示嵌套错误时,你需要嗅探它是数组还是字符串。
¥Since Yup and your custom validation function should always output error messages as strings, you'll need to sniff whether your nested error is an array or a string when you go to display it.
所以...显示 'Must have friends'
和 'Minimum of 3 friends'
(我们示例的数组验证约束)...
¥So...to display 'Must have friends'
and 'Minimum of 3 friends'
(our example's array validation constraints)...
坏的
¥Bad
// within a `FieldArray`'s renderconst FriendArrayErrors = errors =>errors.friends ? <div>{errors.friends}</div> : null; // app will crash
好的
¥Good
// within a `FieldArray`'s renderconst FriendArrayErrors = errors =>typeof errors.friends === 'string' ? <div>{errors.friends}</div> : null;
对于嵌套字段错误,你应该假设对象的任何部分都未定义,除非你已检查过它。因此,你可能想帮自己一个忙,制作一个如下所示的自定义 <ErrorMessage />
组件:
¥For the nested field errors, you should assume that no part of the object is defined unless you've checked for it. Thus, you may want to do yourself a favor and make a custom <ErrorMessage />
component that looks like this:
import { Field, getIn } from 'formik';const ErrorMessage = ({ name }) => (<Fieldname={name}render={({ form }) => {const error = getIn(form.errors, name);const touch = getIn(form.touched, name);return touch && error ? error : null;}}/>);// Usage<ErrorMessage name="friends[0].name" />; // => null, 'too short', or 'required'
注意:在 Formik v0.12 / 1.0 中,可能会向 Field
和 FieldArray
添加新的 meta
属性,它将为你提供相关元数据,例如 error
和 touch
,这将使你不必使用 Formik 或 lodash 的 getIn 或检查路径是否已定义 靠你自己。
¥NOTE: In Formik v0.12 / 1.0, a new meta
prop may be added to Field
and FieldArray
that will give you relevant metadata such as error
& touch
, which will save you from having to use Formik or lodash's getIn or checking if the path is defined on your own.
¥FieldArray Helpers
以下方法可通过渲染属性使用。
¥The following methods are made available via render props.
push: (obj: any) => void
:将值添加到数组末尾
¥push: (obj: any) => void
: Add a value to the end of an array
swap: (indexA: number, indexB: number) => void
:交换数组中的两个值
¥swap: (indexA: number, indexB: number) => void
: Swap two values in an array
move: (from: number, to: number) => void
:将数组中的元素移动到另一个索引
¥move: (from: number, to: number) => void
: Move an element in an array to another index
insert: (index: number, value: any) => void
:将给定索引处的元素插入数组
¥insert: (index: number, value: any) => void
: Insert an element at a given index into the array
unshift: (value: any) => number
:将一个元素添加到数组的开头并返回其长度
¥unshift: (value: any) => number
: Add an element to the beginning of an array and return its length
remove<T>(index: number): T | undefined
:删除数组索引处的元素并返回
¥remove<T>(index: number): T | undefined
: Remove an element at an index of an array and return it
pop<T>(): T | undefined
:从数组末尾删除并返回值
¥pop<T>(): T | undefined
: Remove and return value from the end of the array
replace: (index: number, value: any) => void
:将给定索引处的值替换到数组中
¥replace: (index: number, value: any) => void
: Replace a value at the given index into the array
¥FieldArray render methods
使用 <FieldArray />
渲染事物有三种方法
¥There are three ways to render things with <FieldArray />
<FieldArray name="..." component>
<FieldArray name="..." render>
<FieldArray name="..." children>
render: (arrayHelpers: ArrayHelpers) => React.ReactNode
import React from 'react';import { Formik, Form, Field, FieldArray } from 'formik'export const FriendList = () => (<div><h1>Friend List</h1><FormikinitialValues={{ friends: ['jared', 'ian', 'brent'] }}onSubmit={...}render={formikProps => (<FieldArrayname="friends"render={({ move, swap, push, insert, unshift, pop }) => (<Form>{/*... use these however you want */}</Form>)}/>/></div>);
component: React.ReactNode
import React from 'react';import { Formik, Form, Field, FieldArray } from 'formik'export const FriendList = () => (<div><h1>Friend List</h1><FormikinitialValues={{ friends: ['jared', 'ian', 'brent'] }}onSubmit={...}render={formikProps => (<FieldArrayname="friends"component={MyDynamicForm}/>)}/></div>);// In addition to the array helpers, Formik state and helpers// (values, touched, setXXX, etc) are provided through a `form`// propexport const MyDynamicForm = ({move, swap, push, insert, unshift, pop, form}) => (<Form>{/** whatever you need to do */}</Form>);
children: func
import React from 'react';import { Formik, Form, Field, FieldArray } from 'formik'export const FriendList = () => (<div><h1>Friend List</h1><FormikinitialValues={{ friends: ['jared', 'ian', 'brent'] }}onSubmit={...}render={formikProps => (<FieldArray name="friends">{({ move, swap, push, insert, unshift, pop, form }) => {return (<Form>{/*... use these however you want */}</Form>);}}</FieldArray>)}/></div>);