🎨 ブロックオーバーライドガイド
✨ 概要
CreateOrganizationコンポーネントは、ブロックオーバーライドを通じて強力なカスタマイズ機能を提供します。このパターンでは、共有のフォーム状態処理を維持しながら、フォーム構造と UI コンポーネントをカスタマイズできます。
🚀 基本的なオーバーライドパターン
function Example() {
const defaultData = {
applicationUserName: '',
applicationUserEmail: '',
applicationUserPhoneNumber: '',
companyName: '',
postcode: '',
cityTownVillage: '',
townStreetBuilding: '',
representivePersonName: '',
representativePhoneNumber: '',
companyUrl: '',
additionalInformation: '',
establishmentDate: '',
prefecture: '',
capital: '',
numberOfEmployees: '',
userAgreement: '',
privacyPolicy: '',
};
const [data, setData] = React.useState(defaultData);
return (
<CreateOrganization data={data} onDataChange={setData}>
{({ defaultBlocks, defaultBlockOrder }) => ({
blocks: {
...defaultBlocks,
customNotice: (
<div
style={{
width: '100%',
border: '1px solid #cddcff',
borderRadius: 8,
padding: 12,
background: '#eef4ff',
fontSize: 14,
}}
>
ブロックオーバーライドパターンで追加されたカスタム通知
</div>
),
},
blockOrder: ['customNotice', ...defaultBlockOrder],
})}
</CreateOrganization>
);
}
🔧 完全なカスタマイズ例
CreateOrganization を使った、実際の深いネストのブロックオーバーライド例です:
ライブエディター
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, title: { ...defaultBlocks.title, props: { ...defaultBlocks.title.props, children: '組織への申請', }, }, description: { ...defaultBlocks.description, props: { ...defaultBlocks.description.props, children: '以下のフォームを使って新しい組織を登録します。', }, }, form: { ...defaultBlocks.form, props: { ...defaultBlocks.form.props, children({ defaultBlocks: formBlocks, defaultBlockOrder: formBlockOrder }) { return { blocks: { ...formBlocks, accountHolder: { ...formBlocks.accountHolder, props: { ...formBlocks.accountHolder.props, children({ defaultBlocks: accountHolderBlocks, defaultBlockOrder: accountHolderBlockOrder }) { return { blocks: { ...accountHolderBlocks, sectionTitle: { ...accountHolderBlocks.sectionTitle, props: { ...accountHolderBlocks.sectionTitle.props, children: 'アカウント保有者', }, }, emailField: { ...accountHolderBlocks.emailField, props: { ...accountHolderBlocks.emailField.props, label: 'メールアドレス', }, }, }, blockOrder: accountHolderBlockOrder, }; }, }, }, companyInformation: { ...formBlocks.companyInformation, props: { ...formBlocks.companyInformation.props, children({ defaultBlocks: companyInformationBlocks, defaultBlockOrder: companyInformationBlockOrder, }) { return { blocks: { ...companyInformationBlocks, sectionTitle: { ...companyInformationBlocks.sectionTitle, props: { ...companyInformationBlocks.sectionTitle.props, children: '会社情報', }, }, companyAddress: { ...companyInformationBlocks.companyAddress, props: { ...companyInformationBlocks.companyAddress.props, children({ defaultBlocks: companyAddressBlocks, defaultBlockOrder: companyAddressBlockOrder, }) { return { blocks: { ...companyAddressBlocks, locationTitle: { ...companyAddressBlocks.locationTitle, props: { ...companyAddressBlocks.locationTitle.props, children: '本社所在地', }, }, postCode: { ...companyAddressBlocks.postCode, props: { ...companyAddressBlocks.postCode.props, searchAddressLabel: '住所を検索', }, }, representativeContact: { ...companyAddressBlocks.representativeContact, props: { ...companyAddressBlocks.representativeContact.props, placeholder: '代表者の電話番号', }, }, }, blockOrder: companyAddressBlockOrder, }; }, }, }, companyCapital: { ...companyInformationBlocks.companyCapital, props: { ...companyInformationBlocks.companyCapital.props, label: '払込資本', }, }, companySize: { ...companyInformationBlocks.companySize, props: { ...companyInformationBlocks.companySize.props, label: 'チーム規模', }, }, }, blockOrder: companyInformationBlockOrder, }; }, }, }, compliance: { ...formBlocks.compliance, props: { ...formBlocks.compliance.props, children({ defaultBlocks: complianceBlocks, defaultBlockOrder: complianceBlockOrder }) { return { blocks: { ...complianceBlocks, checkUserAgreement: { ...complianceBlocks.checkUserAgreement, props: { ...complianceBlocks.checkUserAgreement.props, label: ( <> <strong>利用規約</strong>に同意します。 </> ), }, }, checkPrivacyAgreement: { ...complianceBlocks.checkPrivacyAgreement, props: { ...complianceBlocks.checkPrivacyAgreement.props, label: ( <> <strong>プライバシーポリシー</strong>に同意します。 </> ), }, }, }, blockOrder: complianceBlockOrder, }; }, }, }, submitButton: { ...formBlocks.submitButton, props: { ...formBlocks.submitButton.props, children: '組織を送信', }, }, }, blockOrder: formBlockOrder, }; }, }, }, }, blockOrder: defaultBlockOrder, })} </CreateOrganization> ); }
結果
Loading...
🎯 主要なオーバーライド概念
1. ブロックオーバーライド構造
blocks: コンポーネント定義を含むオブジェクトblockOrder: レンダリング順序を制御する配列defaultBlocks: 元のコンポーネント構造defaultBlockOrder: 元のレンダリング順序
2. ネストされたオーバーライド
form: {
...defaultBlocks.form,
props: {
...defaultBlocks.form.props,
children({defaultBlocks, defaultBlockOrder}) {
// ネストされたブロックオーバーライドをここで実行
}
}
}
3. カスタムコンポーネント
デフォルトブロックを完全にカスタムコンポーネントに置き換えます:
customField: <MyCustomComponent {...props} />
📐 ベストプラクティス
- 常にデフォルトの props を展開する ことで既存機能を維持する
- 意味のあるブロック名を使う ことで保守性を高める
- blockOrder の一貫性を維持する(意図的に順序を変える場合を除く)
- カスタムフィールドに適切なバリデーションを実装する
- 読み込み状態とエラー状態を適切に処理する
🚀 利点
- 🎨 完全な UI 制御: フォームのあらゆる側面をカスタマイズできる
- 🔧 柔軟なバリデーション: カスタムバリデーションロジックを実装できる
- 📱 レスポンシブデザイン: レスポンシブな動作を維持できる
- 🔄 状態管理: フォーム状態を完全に制御できる
プロのヒント: 小さなオーバーライドから始めて、徐々に複雑さを増やしましょう。ブロックオーバーライドパターンは強力ですが、props の展開とコンポーネント構造に細心の注意が必要です。