これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の20日目の記事です。
react-jsonschema-form (RJSF) では、 uiSchemaに自作の option
を定義することで、特定のWidgetに独自の値を渡すことができます。
詳細については、Advent Calendar 7日目の記事でふれました。
react-jsonschema-formにて、Widgetをカスタマイズしてみる - メモ的な思考的な
ただ、「すべてのWidgetやFieldに独自の値を渡したい」という場合は、自作の option
ではなかなか厳しそうです。
そんな場合に使えるのが、Formコンポーネントのprops formContext
です。
formContext | <Form />
Props | react-jsonschema-form
公式ドキュメントでは、「各種テーマの設定値をformContextで渡す」例が記載されています。
- AntD Customization | react-jsonschema-form
- formContext | Semantic-UI Customization | react-jsonschema-form
とはいえ、各種テーマ以外でも formContext
は使えます。
そこで今回は
formContext
にfontSize
を渡す- 各WidgetやFieldで
fontSize
を取り出し、styleとして設定
を行い、機能全体でフォントサイズを統一できるようにしてみます。
これにより、 formContext
の値を自作のWidgetやFieldで使用できることが確認できるはずです。
目次
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
formContext へ設定した値を自作のWidgetやFieldに渡す流れ
WidgetProps や FieldProps の型定義を確認する
せっかくなので、今回はWidgetやFieldのPropsの型である
- WidgetProps
- FieldProps
にも型引数を定義してみます。
Githubで型を見ると、それぞれ以下の場所にありました。
- WidgetProps型
- FieldProps型
両方とも型引数は同じで、
- T
- formDataの型
- S
- RJSFSchemaの型
- F
- formContextの型
をそれぞれ渡してあげれば良さそうでした。
Typescript Support | react-jsonschema-form
JSON Schemaの用意
今回は inputWidget
と inputField
の2つの入力項目を持つフォームを用意します。
そのため、今回使用するJSON Schemaは以下となります。
const schema: RJSFSchema = { title: "Using Form Context Form", type: "object", properties: { inputWidget: { type: "number", title: "Input Number Title" }, inputField: { type: "string", } } }
formDataとformContextの型を用意
JSON Schemaにて、入力項目は2つあり、型も定義しました。
それに従い、formDataの型を定義します。
export type UsingFormContextFormField = { inputWidget: number inputField: string }
また、formContextで fontSize
を渡すための型も定義します。
export type MyFormContext = { fontSize: number }
Widgetの用意
準備ができたので、まずは自作Widgetを用意します。
WidgetPropsから formContext
や label
を取り出し、必要なところへ設定しています。
なお、WidgetPropsから取り出せるものは以下に記載があります。
https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-widgets-fields#adding-your-own-custom-widgets
import {RJSFSchema, WidgetProps} from "@rjsf/utils"; import {MyFormContext, UsingFormContextFormField} from "./UsingFormContextForm"; type Props = WidgetProps<UsingFormContextFormField, RJSFSchema, MyFormContext> export const MyFormContextWidget = ({formContext: {fontSize}, label, onChange}: Props) => { // 元々のonChangeを呼んでformDataに反映する const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value) return ( <> <label htmlFor="numberInput" style={{fontSize: fontSize}}>{label}</label> <input id="numberInput" type="number" style={{fontSize: fontSize}} onChange={handleChange} /> </> ) }
Fieldの用意
続いて、自作Fieldを用意します。
こちらはMUIのTypographyやReactのinputを組み合わせています。
なお、FieldPropsから取り出せるものは以下に記載があります。
https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-widgets-fields#field-props
import {FieldProps, RJSFSchema} from "@rjsf/utils"; import Typography from '@mui/material/Typography'; import {MyFormContext, UsingFormContextFormField} from "./UsingFormContextForm"; type Props = FieldProps<UsingFormContextFormField, RJSFSchema, MyFormContext> export const MyFormContextField = ({formContext: {fontSize}, title, onChange}: Props ) => { // 元々のonChangeを呼んでformDataに反映する const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value) return ( <> <Typography sx={{ fontSize: fontSize }} > Typography Title: {title} </Typography> <input type="string" style={{fontSize: fontSize}} onChange={handleChange} /> </> ) }
formContextなどのpropsをFormコンポーネントへ設定
最後に、uiSchema・RegistryWidgetsType・RegistryFieldsTypeなどを用意し、Formコンポーネントのpropsへ設定します。
それに加え、props formContext
にも値を設定します。
今回はキー fontSize
に対して値 40
を設定し、各WidgetやFieldのfontSizeを 40
に統一してみます。
const widgets: RegistryWidgetsType = { myCustomWidget: MyFormContextWidget } const fields: RegistryFieldsType = { myCustomField: MyFormContextField } const uiSchema: UiSchema = { inputField: { "ui:field": "myCustomField" }, inputWidget: { "ui:widget": "myCustomWidget", } } // 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} uiSchema={uiSchema} widgets={widgets} fields={fields} validator={validator} onSubmit={onSubmit} formContext={{ fontSize: 40 }} /> </div> )
動作確認
準備ができたので動作確認します。
すると、WidgetやFieldが formContext
から fontSize
の値が取得できたようで、各コンポーネントのfontSizeが 40
となりました。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/18