跳到主要内容

useModalForm

useModalForm hook allows you to manage a form within a modal. It provides some useful methods to handle the form modal.

信息

useModalForm hook is extended from useForm from the @pankod/refine-react-hook-form package.

Usage​

We'll show two examples, one for creating and one for editing a post. Let's see how useModalForm is used in both.

Before we start, let's create a basic <Modal> component.

src/components/modal.tsx
type ModalPropsType = {
isOpen: boolean;
onClose: () => void;
};

export const Modal: React.FC<ModalPropsType> = ({
isOpen,
onClose,
children,
}) => {
if (!isOpen) return null;
return (
<>
<div className="overlay" onClick={onClose}></div>
<div className="modal">
<div className="modal-title">
<button className="close-button" onClick={onClose}>
&times;
</button>
</div>
<div className="modal-content">{children}</div>
</div>
</>
);
};
See styles
src/styles.css
* {
box-sizing: border-box;
}

.overlay {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1000;
}

.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
z-index: 1000;
width: 500px;
overflow-y: auto;
}

.modal .modal-title {
display: flex;
justify-content: flex-end;
padding: 4px;
}

.modal .modal-content {
padding: 0px 16px 16px 16px;
}

.form {
display: flex;
flex-direction: column;
gap: 8px;
}

.form .form-group {
display: flex;
flex-direction: column;
gap: 4px;
}

.form input,
select,
textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}

Create Modal​

We'll create a PostList page that will display a list of posts. It will also display a <CreatePost> modal that will allow us to create a new post. We'll use useModalForm to manage the modal.

src/pages/posts/list.tsx
import { useTable } from "@pankod/refine-core";
import { useModalForm } from "@pankod/refine-react-hook-form";

import { CreatePost, EditPost } from "components";

export const PostList: React.FC = () => {
const { tableQueryResult } = useTable<IPost>({
initialSorter: [
{
field: "id",
order: "desc",
},
],
});

const createModalFormReturnValues = useModalForm({
refineCoreProps: { action: "create" },
});

const {
modal: { show: showCreateModal },
} = createModalFormReturnValues;

return (
<div>
<CreatePost {...createModalFormReturnValues} />
<button onClick={() => showCreateModal()}>Create Post</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{tableQueryResult.data?.data.map((post) => (
<tr key={post.id}>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{post.status}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

interface IPost {
id: number;
title: string;
status: "published" | "draft" | "rejected";
}

<CreatePost> component will be used to create a new post.

src/components/post/create.tsx
import { UseModalFormReturnType } from "@pankod/refine-react-hook-form";

import { Modal } from "../modal";

export const CreatePost: React.FC<UseModalFormReturnType> = ({
register,
formState: { errors },
refineCore: { onFinish, formLoading },
handleSubmit,
modal: { visible, close },
saveButtonProps,
}) => {
return (
<Modal isOpen={visible} onClose={close}>
<form className="form" onSubmit={handleSubmit(onFinish)}>
<div className="form-group">
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</div>
<div className="form-group">
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</div>
<div className="form-group">
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
/>
{errors.content && <span>{errors.content.message}</span>}
</div>
<button type="submit" {...saveButtonProps}>
{formLoading ? "Loading" : "Save"}
</button>
</form>
</Modal>
);
};
Create Modal

Edit Modal​

Now we'll create a <EditPost> component that will allow us to edit a post within the modal. Also, we'll add a button to specify that wich post to edit.

src/pages/posts/list.tsx
import { useTable } from "@pankod/refine-core";
import { useModalForm } from "@pankod/refine-react-hook-form";

import { CreatePost, EditPost } from "components";
import { IPost } from "interfaces";

export const PostList: React.FC = () => {
const { tableQueryResult } = useTable<IPost>({
initialSorter: [
{
field: "id",
order: "desc",
},
],
});

const createModalFormReturnValues = useModalForm({
refineCoreProps: { action: "create" },
});
const editModalFormReturnValues = useModalForm({
refineCoreProps: { action: "edit" },
});

const {
modal: { show: showCreateModal },
} = createModalFormReturnValues;
const {
modal: { show: showEditModal },
} = editModalFormReturnValues;

return (
<div>
<CreatePost {...createModalFormReturnValues} />
<EditPost {...editModalFormReturnValues} />
<button onClick={() => showCreateModal()}>Create Post</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{tableQueryResult.data?.data.map((post) => (
<tr key={post.id}>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{post.status}</td>
<td>
<button onClick={() => showEditModal(post.id)}>
Edit
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

<EditPost> component will be used to edit a post.

src/components/post/edit.tsx
import { UseModalFormReturnType } from "@pankod/refine-react-hook-form";

import { Modal } from "components/modal";

export const EditPost: React.FC<UseModalFormReturnType> = ({
register,
formState: { errors },
refineCore: { onFinish, formLoading },
handleSubmit,
modal: { visible, close },
saveButtonProps,
}) => {
return (
<Modal isOpen={visible} onClose={close}>
<form className="form" onSubmit={handleSubmit(onFinish)}>
<div className="form-group">
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</div>
<div className="form-group">
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</div>
<div className="form-group">
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
/>
{errors.content && <span>{errors.content.message}</span>}
</div>
<button type="submit" {...saveButtonProps}>
{formLoading ? "Loading" : "Save"}
</button>
</form>
</Modal>
);
};
Edit Modal

API Reference​

Properties​

*: These properties have default values in RefineContext and can also be set on the <Refine> component.

External Props

It also accepts all props of useForm hook available in the React Hook Form.

Return values​

PropertyDescriptionType
modalRelevant states and methods to control the modalModalReturnValues
refineCoreThe return values of the useForm in the coreUseFormReturnValues
React Hook Form Return ValuesSee React Hook Form documentation

  • ModalReturnValues​

PropertyDescriptionType
visibleState of modal visibilityboolean
showSets the visible state to true(id?: BaseKey) => void
closeSets the visible state to false() => void
submitSubmits the form(values: TVariables) => void
titleModal title based on resource and action valuestring
saveButtonPropsProps for a submit button{ disabled: boolean, onClick: (e: React.BaseSyntheticEvent) => void; }

Live StackBlitz Example​