React でバリデーション付きのモーダルを出したい
データを確認したり、更新するためのUIとして、下図のような感じでバリデーション付きのモーダルが欲しいと思いました。でも自分でイチからは作りたくない。そして、複数のライブラリを組み合わせることもしたくないと思いました。
そうしたら、よさそうなのがありました。Ant Design です。上の図はそれで試してみた結果です。
コード
次のようにやりました(Code Sandobox参照)。
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Button, Modal, Form, Input, Radio } from "antd";
const MemberEditForm = ({ visible, member, onCreate, onCancel }) => {
const [form] = Form.useForm();
return (
<Modal
visible={visible}
title="メンバー情報の編集"
okText="更新"
cancelText="キャンセル"
onCancel={onCancel}
onOk={() => {
form
.validateFields()
.then((values) => {
onCreate(values);
})
.catch((info) => console.log("バリデーション失敗:", info));
}}
>
<Form
form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
name: member.name,
title: member.title,
bio: member.bio,
email: member.email,
canSee: member.canSee
}}
>
<Form.Item
name="name"
label="名前"
rules={[
{
required: true,
message: "名前を入力してください。"
}
]}
>
<Input />
</Form.Item>
<Form.Item
name="title"
label="タイトル"
rules={[
{
required: true,
message: "タイトルを入力してください。"
}
]}
>
<Input />
</Form.Item>
<Form.Item name="bio" label="プロフィール">
<Input.TextArea autoSize="true" />
</Form.Item>
<Form.Item
name="email"
label="メールアドレス"
rules={[
{
required: false,
type: "email",
message: "Eメールアドレスとして適切なものを入力してください。"
}
]}
>
<Input placeholder="abc@pitang1965.com" />
</Form.Item>
<Form.Item name="canSee" className="member-edit-form_last-form-item">
<Radio.Group>
<Radio value="public">公開</Radio>
<Radio value="private">非公開</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Modal>
);
};
const MemberPage = () => {
const [visible, setVisible] = useState(false);
const [member, setMember] = useState({
name: "yoko",
title: "浪人",
bio:
"Web、ナレーション、動画制作であなたにウフ 💓 を。イベント盛り上げ隊!",
email: "yoko@abc.com",
canSee: "private"
});
const onCreate = (values) => {
console.log("Received values of form: ", values);
setVisible(false);
setMember((prev) => ({ ...prev, ...values }));
};
return (
<div>
<h1>{member.name}</h1>
<p>タイトル: {member.title}</p>
<p>プロフィール: {member.bio}</p>
<p>メールアドレス: {member.email}</p>
<p>{member.canSee === "public" ? "公開" : "非公開"}</p>
<Button type="primary" onClick={() => setVisible(true)}>
編集
</Button>
<MemberEditForm
visible={visible}
member={member}
onCreate={onCreate}
onCancel={() => {
setVisible(false);
}}
/>
</div>
);
};
ReactDOM.render(<MemberPage />, document.getElementById("container"));
躓いたポイント
初期値の与え方
各フィールド(例:名前、メールアドレス)は、<Form.Item>内の<Input>で defaultValue プロパティで与えることができるのですが、警告が出ます。<Form>内で使うには、次のように inialValues プロパティを使う必要がありました。
<Form
form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
name: member.name,
title: member.title,
bio: member.bio,
email: member.email,
canSee: member.canSee ? "public" : "private"
}}
>
useStateの使い方
モーダルで変更された値を反映されるには次のようにします。
const [member, setMember] = useState({
name: "yoko",
title: "浪人",
bio:
"Web、ナレーション、動画制作であなたにウフ 💓 を。イベント盛り上げ隊!",
email: "yoko@abc.com",
canSee: "private"
});
:
:
const onCreate = (values) => {
console.log("Received values of form: ", values);
setVisible(false);
setMember((prev) => ({ ...prev, ...values })); <----- ★これ!
};
再度モーダルが表示されるときの初期値
下記コメントアウトしたコードがあると、1回目に表示されるときの値が表示されてしまいます。
const MemberEditForm = ({ visible, member, onCreate, onCancel }) => {
const [form] = Form.useForm();
return (
<Modal
visible={visible}
title="メンバー情報の編集"
okText="更新"
cancelText="キャンセル"
onCancel={onCancel}
onOk={() => {
form
.validateFields()
.then((values) => {
form.resetFields(); <----- ★これ!
onCreate(values);
})
.catch((info) => console.log("バリデーション失敗:", info));
}}
>
詳細は詳しいドキュメントに書かれています。
ディスカッション
コメント一覧
まだ、コメントがありません