<FieldArray />

<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>
<Formik
initialValues={{ friends: ['jared', 'ian', 'brent'] }}
onSubmit={values =>
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
}, 500)
}
render={({ values }) => (
<Form>
<FieldArray
name="friends"
render={arrayHelpers => (
<div>
{values.friends && values.friends.length > 0 ? (
values.friends.map((friend, index) => (
<div key={index}>
<Field name={`friends.${index}`} />
<button
type="button"
onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
>
-
</button>
<button
type="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 对象数组

¥FieldArray Array of Objects

你还可以通过遵循 <FieldArray /><Field /><input /> 元素的名称属性的 object[index].propertyobject.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>
<FieldArray
name="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>
))}
<button
type="button"
onClick={() => arrayHelpers.push({ name: '', age: '' })}
>
+
</button>
</div>
)}
/>
</Form>

FieldArray 验证陷阱

¥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 precedence
salary: 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 render
const FriendArrayErrors = errors =>
errors.friends ? <div>{errors.friends}</div> : null; // app will crash

好的

¥Good

// within a `FieldArray`'s render
const 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 }) => (
<Field
name={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 中,可能会向 FieldFieldArray 添加新的 meta 属性,它将为你提供相关元数据,例如 errortouch,这将使你不必使用 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 渲染方法

¥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>
<Formik
initialValues={{ friends: ['jared', 'ian', 'brent'] }}
onSubmit={...}
render={formikProps => (
<FieldArray
name="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>
<Formik
initialValues={{ friends: ['jared', 'ian', 'brent'] }}
onSubmit={...}
render={formikProps => (
<FieldArray
name="friends"
component={MyDynamicForm}
/>
)}
/>
</div>
);
// In addition to the array helpers, Formik state and helpers
// (values, touched, setXXX, etc) are provided through a `form`
// prop
export 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>
<Formik
initialValues={{ 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>
);
Formik 中文网 - 粤ICP备13048890号