これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の10日目の記事です。
この記事では、react-jsonschema-form (RJSF) の公式ドキュメントでバリデーションまわりを見てみます。
Validation | react-jsonschema-form
その後、RJSFのバリデーションをカスタマイズしてみます。
目次
- 環境
- RJSFのバリデーションについて
- HTMLのバリデーションを無効にする
- リアルタイムバリデーション(ライブバリデーション)する
- バリデーションのカスタムルールを追加する
- バリデーションのエラーメッセージを変更する
- ソースコード
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
RJSFのバリデーションについて
RJSFのバリデーションとしては
- HTMLのバリデーション
- Ajvの8系を使ったバリデーション
が用意されています。
また、要望に応じて、それらのバリデーションをカスタマイズすることもできます。
今回は、上記2つのバリデーションについて、もう少し見ていきます。
HTMLのバリデーションについて
HTMLのバリデーションとは、以下のMDNにあるようなHTMLのフォーム検証となります。
JSON Schemaにて type
や format
を指定することにより、RJSFが適切なHTMLタグを生成してHTMLのバリデーションが行われます。
なお、HTMLのバリデーションは無効化することもできます。これは後で見ていきます。
HTML5 Validation | Validation | react-jsonschema-form
Ajvの8系を使ったバリデーションについて
RJSFでは、 Ajv
ライブラリを使って JSON Schema に対するバリデーションを行っています。
Ajv
の公式サイトに Ajv JSON schema validator
とある通り、JSON Schema のバリデーションを行うライブラリです。
Ajv JSON schema validator
AjvがサポートしているJSON Schemaのバージョンは以下に記載があります。
JSON Schema | Ajv JSON schema validator
Ajvのdefault exportでは draft 7
が使われるようです。
簡単ではありますがRJSFのバリデーションの概要を見ました。
次は、RJSFのバリデーションを見ていきます。
HTMLのバリデーションを無効にする
HTMLのバリデーションを無効にするには、Fomのprops noHtml5Validate
を true
にします。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#html5-validation
まずはHTMLのバリデーションが有効な時の状態です。
JSON Schemaで requred
を指定しておきます。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; export const EnabledHtml5ValidationForm = () => { const schema: RJSFSchema = { title: "Enabled HTML5 Validation Form", type: "object", required: ["stringInput"], properties: { stringInput: { type: "string", } } } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} /> </div> ) }
動作を確認します。何も入力せずにsubmitすると、HTMLによるエラーが表示されます。
続いて、Formのpropsに noHtml5Validate
を追加します。
<Form schema={schema} validator={validator} noHtml5Validate />
この状態で何も入力せずにsubmitすると、HTMLによるエラーではなく、RJSFによるエラーが表示されます。
リアルタイムバリデーション(ライブバリデーション)する
RJSFでリアルタイムバリデーション(ライブバリデーション)を行う場合、Formのprops liveValidate
を使うことで実現できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#live-validation
実際にためしてみます。今回は
- 入力欄は、最低3文字の入力が必要
- Formに
liveValidate
を追加
とします。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; export const LiveValidationForm = () => { const schema: RJSFSchema = { title: "Live Validation Form", type: "object", required: [], properties: { stringInput: { type: "string", minLength: 3 } } } // onSubmitの引数の説明は以下 // https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onsubmit const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} onSubmit={onSubmit} liveValidate /> </div> ) }
動作を確認します。ab
という2文字入力時点ではエラーが表示されています。
3文字目の c
を入力すると、バリデーションエラーではなくなったため、エラーメッセージが非表示となりました。
バリデーションのカスタムルールを追加する
JSON Schemaに書くことである程度のバリデーションは実現できます。
ただ、もう少し詳しいバリデーションや複数項目を組み合わせた時のバリデーションを行いたいときもあります。
その場合は、バリデーションのカスタムルールを追加することで実現できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#custom-validation-rules
今回は rangeFrom
と rangeTo
の2項目を追加し、 rangeFrom > rangeTo
の場合にエラーとなるバリデーションを追加します。
まずはバリデーションルールの関数を用意します。関数のインタフェースは公式ドキュメントに従います。
const customValidate = (formData: FormData, errors: FormValidation<FormData>): FormValidation<FormData> => { console.log(formData) if (formData.rangeFrom > formData.rangeTo) { // rangeToはrequiredなバリデーションの後にここへ来るので、今回は `!` を使っておく errors.rangeTo!.addError("rangeTo must be greater than rangeFrom") } return errors }
続いて、Formのprops customValidate
にバリデーションルールの関数を渡します。
<Form schema={schema} validator={validator} customValidate={customValidate} />
動作を確認します。バリデーションエラーとなるような入力をすると、画面にメッセージが表示されました。
なお、integer型の項目に 3.4
を入れるなど、JSON Schemaのバリデーションエラーとなる値を入力した場合は、そのエラーも同時に表示されます。
バリデーションのエラーメッセージを変更する
RJSFではバリデーションエラーとなった時のメッセージが用意されています。
もし、エラーメッセージを変更したい場合にはカスタマイズできます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#custom-error-messages
まず、エラーメッセージを変換する関数を用意します。
差し替えるerrorレコードであった場合に
- message
- デフォルトでは、入力項目の下に表示されるエラーメッセージ
- stack
- デフォルトでは、一番上の
Errors
に表示されるエラーメッセージ
- デフォルトでは、一番上の
などを差し替えます。
ちなみに、errorオブジェクトには以下のようなデータが渡されてきます。
{ "name": "format", "property": ".stringInput", "message": "must match format \"email\"", "params": { "format": "email" }, "stack": ".stringInput must match format \"email\"", "schemaPath": "#/properties/stringInput/format" }
今回は、入力項目 stringInput
のエラーが format
であった場合に、エラーメッセージを差し替えるようにします。
const transformErrors = (errors: RJSFValidationError[], _uiSchema: typeof schema) => { console.log(errors) return errors.map((error) => { if (error.property === '.stringInput' && error.name === 'format') { error.message = 'My email error message' error.stack = 'Stack error message' } return error }) }
続いて、Formのprop transformErrors
に関数を指定します。
なお、 email
の場合HTMLバリデーションが実行されてしまうので、今回の動作確認ではHTMLバリデーションを無効化しておきます。
<Form schema={schema} validator={validator} transformErrors={transformErrors} noHtml5Validate />
動作を確認します。emailとして不適切な値を入力すると、差し替えたエラーメッセージが表示されました。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/9