<FieldArray />

<FieldArray /> は、一般的な配列/リスト操作を支援するコンポーネントです。関連する配列を保持するキーへのパスを `name` プロパティに渡します。<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 オブジェクトの配列

<Field />または<input />要素のname属性にobject[index].propertyまたはobject.index.propertyという規則に従うことで、オブジェクトの配列を反復処理することもできます。

<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では、errortouchなどの関連メタデータを提供する新しいmetaプロップがFieldFieldArrayに追加される可能性があり、FormikやlodashのgetInを使用したり、パスが自分で定義されているかどうかを確認したりする必要がなくなります。

FieldArray ヘルパー

以下のメソッドは、レンダリングプロップスを介して使用できます。

  • push: (obj: any) => void: 配列の最後に値を追加します
  • swap: (indexA: number, indexB: number) => void: 配列内の2つの値を入れ替えます
  • 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 />で項目をレンダリングするには3つの方法があります。

  • <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ニュース、記事、リソースをメールで受信します。

Copyright © 2020 Formium, Inc. All rights reserved.