これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の22日目の記事です。
react-jsonschema-form (RJSF) では、JSON Schemaを元にバリデーションができます。
ただ、バリデーションエラーとなったときに気になる挙動がいくつかあったため、メモを残します。
目次
- 環境
- formDataをstateとして保持していると、バリデーションエラー後、再入力してもバリデーションエラーが消えない
- 日付データをformDataとして設定する時のフォーマットについて
- バリデーションエラーになると、ブラウザのコンソールにエラーが出力される
- ソースコード
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
formDataをstateとして保持していると、バリデーションエラー後、再入力してもバリデーションエラーが消えない
現象
RJSFでは、バリデーションエラーになった後、そのエラーとなった項目に再入力することでエラーが消えるような挙動をします。
バリデーションエラー発生
1文字入力すると、エラーが消える
ただ、
- フォームの入力値である
formData
はuseState
を使ったstateとして保持 - フォームにはクリアボタンやデータ更新ボタンがある
- このボタンの中でstateを更新する
とした場合、バリデーションエラー発生後に再度入力してもエラーが残り続けます。
例えば、以下のようなJSON SchemaとFormがあったとします。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; import Stack from "@mui/material/Stack"; import {useState} from "react"; type MyFormData = { stringInput: string } export const NotClearErrorForm = () => { const [formData, setFormData] = useState<MyFormData>({ stringInput: "foo" }) const schema: RJSFSchema = { title: "Not Clear Error Form", type: "object", properties: { stringInput: { type: "string", minLength: 5 } } } // https://stackoverflow.com/questions/1349404/generate-random-string-characters-in-javascript/8084248 const onLoadData = () => setFormData({stringInput: Math.random().toString(32).substring(2) }) const onClear = () => setFormData({stringInput: ""}) return ( <div style={{width: '400px'}}> <Form schema={schema} formData={formData} validator={validator} > <Stack direction={"row"} spacing={2}> <button type="submit">Submit</button> <button type="button" onClick={onLoadData}>Load another data</button> <button type="button" onClick={onClear}>Clear</button> </Stack> </Form> </div> ) }
stateをFormの formData
に渡しているため、初期表示ではデータが存在します。
この状態でsubmitすると、JSON Schemaの minLength: 5
に違反しているため、バリデーションエラーになります。
しかし、バリデーションエラー後、Load another data
ボタンを押しても、バリデーションエラーは消えません。
その後、再度入力するとバリデーションエラーが消えます。
上記の例では、 X
を追加入力したところエラーが消えました。
これは clear
ボタンを押したときも同様です。
対応
Githubのissueにコメントがありました。
Formの key
を更新することで、Formのインスタンスを差し替えれば回避できるそうです。
From what I can see so far, errors are internal state so there is no way to clear it except creating a new form instance by changing element key.
そこで、
- stateに
formData
とkey
の2つの値をもたせる - ボタンクリック時に、 formDataに加え、keyも更新する
とします。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; import Stack from "@mui/material/Stack"; import {useState} from "react"; type MyFormData = { stringInput: string } type State = { key: Date formData: MyFormData } export const NotClearErrorFormFixed = () => { // 型と初期値にkeyを加える const [data, setData] = useState<State>({ key: new Date(), formData: { stringInput: "foo" } }) const schema: RJSFSchema = { title: "Fixed: Not Clear Error Form", type: "object", properties: { stringInput: { type: "string", minLength: 5 } } } // keyも更新するよう変更 const onLoadData = () => setData({key: new Date(), formData: { stringInput: Math.random().toString(32).substring(2) }}) const onClear = () => setData({key: new Date(), formData: {stringInput: ""}}) return ( <div style={{width: '400px'}}> <Form key={data.key} // 追加 schema={schema} formData={data.formData} validator={validator} > <Stack direction={"row"} spacing={2}> <button type="submit">Submit</button> <button type="button" onClick={onLoadData}>Load another data</button> <button type="button" onClick={onClear}>Clear</button> </Stack> </Form> </div> ) }
すると、Clearなどのボタンを押したタイミングでエラーメッセージも消えるようになりました。
日付データをformDataとして設定する時のフォーマットについて
現象
RJSFを使う際、外部APIから取得したデータを初期値としてFormの formData
へ設定することがあります。
この時、 2023/12/22
のようなスラッシュ区切りとして設定すると、 formData
に値を設定したにも関わらず、画面には表示されません。
import {RJSFSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; export const DateFormatForm = () => { const schema: RJSFSchema = { title: "Date Format Form", type: "object", properties: { dateInput: { type: "string", format: "date" } } } return ( <div style={{width: '400px'}}> <Form schema={schema} validator={validator} formData={{ dateInput: '2023/12/22' }} /> </div> ) }
表示すると、初期値に何も設定されていません。
対応
ブラウザのコンソールを見るとメッセージが出ています。
The specified value "2023/12/12" does not conform to the required format, "yyyy-MM-dd".
そこで、 formData
を -
区切りで設定します。
<Form schema={schema} validator={validator} formData={{ dateInput: '2023-12-22' }} />
すると、画面に初期値が表示されました。
バリデーションエラーになると、ブラウザのコンソールにエラーが出力される
この件は13日目の記事に書きましたので、そちらを参照ください。
onErrorについて | react-jsonschema-formにて、Formコンポーネントのpropsの設定をカスタマイズしてみる - メモ的な思考的な
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/20