これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の13日目の記事です。
この記事では、react-jsonschema-form (RJSF) が提供している Form
コンポーネントの props
の設定をカスタマイズしてみます。
ただ、Formコンポーネントには多くのpropsが存在するため、ここでは気になったpropsのみ扱います。
Props | react-jsonschema-form
目次
- 環境
- childrenを使って、Formのボタンを増やす
- extraErrorsとextraErrorsBlockSubmitの挙動について
- focusOnFirstErrorについて
- onErrorについて
- noValidateの挙動とdeprecated
- omitExtraDataとは何かとその挙動について
- showErrorListにて、エラーリストの表示位置を変更する
- ソースコード
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
childrenを使って、Formのボタンを増やす
RJSFのデフォルトでは、submitボタンが1つ表示されます。
それ以外にもボタンを増やしたい場合は children
が使えます。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#children
ここでは
- my submit
- my button
の2つのボタンを表示してみます。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; import Stack from "@mui/material/Stack"; import Button from "@mui/material/Button"; export const ChildrenForm = () => { const schema: RJSFSchema = { title: "Children Form", type: "object", required: [], properties: { stringInput: { type: "string" } } } // onSubmitの引数の説明は以下 // https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onsubmit const onSubmit = ({formData}, _event) => { console.log(formData) } const onClick = () => { console.log("my button") } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} > <Stack spacing={2} direction="row"> <Button type="submit" variant="contained">MySubmit</Button> <Button type="button" variant="outlined" onClick={onClick}>MyButton</Button> </Stack> </Form> </div> ) }
動かしてみると、ボタンが2つになりました。
また、Formの submit
やButtonの onClick
も動作しています。
extraErrorsとextraErrorsBlockSubmitの挙動について
extraErrors
propsを使うことで、RJSF以外で発生したバリデーションエラーもRJSFのフォームに表示できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#extraerrors
例えば、「バックエンドでバリデーションを実行し、その結果もフォームに表示する」みたいなときに使えそうです。
関係するpropsは
- extraErrors
- extraErrorsBlockSubmi
の2つがあるため、それらを見ていきます。
extraErrors のみを使うとエラーが表示されるだけでsumitは成功する
まずは extraErrors
のみを使う場合です。
以下の実装では、 foo
と bar
に対して追加のエラーを表示します。
import {ErrorSchema, RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const ExtraErrorsForm = () => { const schema: RJSFSchema = { title: "Extra Errors Form", type: "object", properties: { foo: { type: "object", properties: { bar: { type: "string", const: "bar" } } } } } const onSubmit = ({formData}, _event) => { console.log(formData) } const extraErrors: ErrorSchema = { foo: { __errors: ["foo error"], bar: { __errors: ["bar error"] } } } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} extraErrors={extraErrors} /> </div> ) }
実行した結果です。最初の時点でエラーが表示されています。
ただ、 extraErrors
はエラーを表示するだけです。
そのため、JSON Schema的に正しい値を入力した場合にはエラーとはならず、submitが成功します。
extraErrorsとextraErrorsBlockSubmitを使うと、エラー解消するまでsubmitが成功しない
もし、 extraErrors
に指定したエラーが解消するまでフォームのsubmitが成功しないようにするには、 extraErrorsBlockSubmit
propsも指定します。
<Form schema={schema} validator={validator} onSubmit={onSubmit} extraErrors={extraErrors} extraErrorsBlockSubmit // 追加 />
動かしてみると、extraErrorsにデータがある場合はsubmitが成功しなくなりました。
focusOnFirstErrorについて
RJSFでは、最初にエラーが発生した項目にフォーカスを当てるための props focusOnFirstError
があります。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#focusonfirsterror
このpropsにはbooleanの他にコールバックも渡せるため、各挙動を確認してみます。
focusOnFirstErrorに true を渡した時の挙動
focusOnFirstError
を true
にした場合の挙動を確認します。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const FocusOnFirstErrorForm = () => { const schema: RJSFSchema = { title: "Focus On First Error Form", type: "object", required: [], properties: { foo: { type: "string", const: "foo" }, bar: { type: "string", const: "bar" }, baz: { type: "string", const: "baz" } } } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} focusOnFirstError /> </div> ) }
動かしてみます。
上と真ん中がエラーになるようにしてsubmitすると、上の項目にフォーカスが当たります。
一方、真ん中と下がエラーになるようにしてsubmitすると、真ん中の項目にフォーカスが当たります。
focusOnFirstErrorにコールバックを渡した時の挙動
続いて、 focusOnFirstError
にコールバックを渡した時の挙動を確認します。
JSON Schemaはそのままで、コールバックを追加しFormコンポーネントに渡します。
const callback = (error: RJSFValidationError) => console.log(error) return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} focusOnFirstError={callback} /> </div> )
動かしてみます。
今回も、上と真ん中の項目がエラーになるよう入力してsubmitしたところ、
- フォーカスはどこにも当たらない
- コールバックが実行され、上の項目のエラー内容がコンソールへ出力
となりました。
onErrorについて
onError
propsでは、フォームをsubmitしたときに呼ばれるコールバックを指定できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onerror
このpropsについて気になる部分を確認します。
onErrorに何も設定しないとエラーがコンソール出力される
今までも所々で見えたのですが、RJSFの場合、バリデーションエラーが発生するとブラウザのコンソールにもエラーの内容が出力されます。
例えば、先ほどの focusOnFirstError
propsでエラーを発生させたときには、以下のような内容がコンソール出力されていました。
これは、Formコンポーネントにて「 onError
propsを設定しない状態でエラーが発生した場合、エラーをコンソール出力する」と実装されていることが原因です。
https://github.com/rjsf-team/react-jsonschema-form/blob/v5.15.1/packages/core/src/components/Form.tsx#L827
そのため、もしコンソールにバリデーションを出力したくない場合には、 onError
に何もしない関数を渡すなどの対応が必要です。
例えば、以下のように onError
へ何もしない関数を割り当てます。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const OnErrorForm = () => { const schema: RJSFSchema = { title: "On Error Form", type: "object", required: [], properties: { foo: { type: "string", const: "foo" } } } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onError={()=> {}} /> </div> ) }
すると、フォームにはエラーが出力されますが、コンソールには何も出力されなくなります。
focusOnFirstError にコールバックを渡しつつ、onErrorを設定した場合の挙動
ここまでで、バリデーションエラーをハンドリングできる props として
- focusOnFirstError
- onError
の2つがあると分かりました。
では、両方同時に設定したときにどのような挙動になるか見てみます。
import {RJSFSchema, RJSFValidationError} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const FocusOnFirstErrorAndOnErrorForm = () => { const schema: RJSFSchema = { title: "Focus On First Error And On Error Form", type: "object", required: [], properties: { foo: { type: "string", const: "foo" }, bar: { type: "string", const: "bar" }, baz: { type: "string", const: "baz" } } } const callback = (error: RJSFValidationError) => console.log("callback", error) const onError = (error: RJSFValidationError[]) => console.log("onError", error) return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} focusOnFirstError={callback} onError={onError} /> </div> ) }
動かしてみたところ、両方とも動作しました。違いは
focusOnFirstError
のコールバックには、最初のエラーのみが渡されるonError
のコールバックには、すべてのエラーが渡される
でした。
noValidateの挙動とdeprecated
RJSFでフォームだけ用意してバリデーションをしたくない場合、 noValidate
props に true
を渡します。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#novalidate
ちなみに、公式ドキュメントには記載がありませんが、ソースコードを見ると noValidate
はdeprecatedになっていました。
https://github.com/rjsf-team/react-jsonschema-form/blob/v5.15.1/packages/core/src/components/Form.tsx#L156-L158
そのため、将来的には使えなくなる props
のようです。
では実装です。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const NoValidateForm = () => { const schema: RJSFSchema = { title: "No Validate Form", type: "object", required: [], properties: { stringInput: { type: "string", format: "uuid" } } } const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} noValidate /> </div> ) }
動かしてみると、バリデーションエラーにならず、submitした時のログがコンソールへと出力されました。
omitExtraDataとは何かとその挙動について
最初、 omitExtraData
propsとは何か分からなかったため、公式ドキュメントを読んだところ
If set to true, then extra form data values that are not in any form field will be removed whenever onSubmit is called. Set to false by default.
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#omitextradata
とありました。
これより、 extra form data values that are not in any form field
は、Form の formData
propsで渡すデータと考えました。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#formdata
そこで、Formに formData
でフォームの項目としては存在していないデータを渡した上で、 omitExtraData
を true
にしたときに、どのような挙動になるかを見てみます。
formData のみ設定する場合の挙動
まずは、 formData
のみ設定する場合です。この場合、 omitExtraData
はデフォルトの false
になります。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const OmitExtraDataForm = () => { const schema: RJSFSchema = { title: "Omit Extra Data Form", type: "object", required: [], properties: { stringInput: { type: "string", } } } const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} formData={{ stringInput: "foo", noFieldData: "nothing" }} /> </div> ) }
動かしてみます。
何も変更せずにsubmitすると、formDataで設定した項目のうち、フォームの項目として存在しないものもコンソールへ出力されました。
formData と omitExtraData を設定する場合の挙動
続いて、 formData
と omitExtraData
の両方を設定してみます。
<Form schema={schema} validator={validator} onSubmit={onSubmit} formData={{ stringInput: "foo", noFieldData: "nothing" }} omitExtraData // 追加 />
ここでも何も変更せずにsubmitしたところ、入力項目のみコンソールへ出力されました。
showErrorListにて、エラーリストの表示位置を変更する
showErrorList
propsを使うことにより、エラーリストの表示位置を変更できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#showerrorlist
デフォルトでは画面上部に表示するため、それ以外の表示を確認します。
画面下部にエラーリストを表示する
showErrorList
を bottom
にします。
<Form schema={schema} validator={validator} showErrorList={"bottom"} />
バリデーションエラーにしたところ、画面下部にエラーリストが表示されました。
画面にエラーリストを表示しない
この場合は、 false
を設定します。
<Form schema={schema} validator={validator} showErrorList={false} />
バリデーションエラーにしたところ、画面にエラーリストは表示されませんでした。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/12