<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><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
中相關鍵的名稱或路徑。
validateOnChange?: boolean
預設值為 true
。決定是否應在任何陣列操作*之後*執行表單驗證。
您也可以透過遵循 object[index].property
或 object.index.property
的慣例,迭代物件陣列,作為 <FieldArray />
中 <Field />
或 <input />
元素的 name 屬性。
<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>
進行驗證可能會很棘手。
如果您使用 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 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'),});
由於 Yup 和您的自定義驗證函式應始終將錯誤訊息輸出為字串,因此當您要顯示巢狀錯誤時,需要檢查它是陣列還是字串。
因此...要顯示 '必須有朋友'
和 '至少 3 個朋友'
(我們範例的陣列驗證限制)...
不良
// within a `FieldArray`'s renderconst FriendArrayErrors = errors =>errors.friends ? <div>{errors.friends}</div> : null; // app will crash
良好
// within a `FieldArray`'s renderconst FriendArrayErrors = errors =>typeof errors.friends === 'string' ? <div>{errors.friends}</div> : null;
對於巢狀欄位錯誤,您應該假設除非您已檢查物件的任何部分,否則它未定義。因此,您不妨自己動手製作一個自定義的 <ErrorMessage />
元件,如下所示
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 或自行檢查路徑是否已定義。
以下方法可透過渲染屬性使用。
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 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>);