<FieldArray />

<FieldArray /> 是一個元件,可協助處理常見的陣列/列表操作。您傳遞一個帶有 name 屬性的路徑,指向 values 中持有相關陣列的鍵。然後,<FieldArray /> 將透過渲染屬性讓您可以使用陣列輔助方法。為了方便起見,呼叫這些方法將觸發驗證,並為您管理 touched 狀態。

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 中相關鍵的名稱或路徑。

validateOnChange?: boolean

預設值為 true。決定是否應在任何陣列操作*之後*執行表單驗證。

FieldArray 物件陣列

您也可以透過遵循 object[index].propertyobject.index.property 的慣例,迭代物件陣列,作為 <FieldArray /><Field /><input /> 元素的 name 屬性。

<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> 進行驗證可能會很棘手。

如果您使用 validationSchema 且您的表單具有陣列驗證需求(例如最小長度)以及巢狀陣列欄位需求,則顯示錯誤可能會很棘手。Formik/Yup 將由內而外顯示驗證錯誤。例如,

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'),
});

由於 Yup 和您的自定義驗證函式應始終將錯誤訊息輸出為字串,因此當您要顯示巢狀錯誤時,需要檢查它是陣列還是字串。

因此...要顯示 '必須有朋友''至少 3 個朋友'(我們範例的陣列驗證限制)...

不良

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

良好

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

對於巢狀欄位錯誤,您應該假設除非您已檢查物件的任何部分,否則它未定義。因此,您不妨自己動手製作一個自定義的 <ErrorMessage /> 元件,如下所示

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 或自行檢查路徑是否已定義。

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

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 新聞、文章和資源,將發送到您的收件匣。

版權所有 © 2020 Formium, Inc. 保留所有權利。