@void-snippets/react
useModal
Create/edit modal state with loading and data discrimination.
#What it does
Manages modal state for both "create" and "edit" flows from a single hook instance. data is null in create mode and the entity in edit mode — one check tells you which mode you're in.
#Signature
typescript
function useModal<T = unknown>(): {
isOpen: boolean;
data: T | null;
isLoading: boolean;
openCreateModal: () => void;
openEditModal: (entity: T) => void;
closeModal: () => void;
setLoading: (loading: boolean) => void;
setModal: (open: boolean, data?: T | null) => void;
}#Example
tsx
function UsersPage() {
const modal = useModal<User>();
const isEditing = modal.data !== null;
return (
<>
<Button onClick={modal.openCreateModal}>+ New User</Button>
<UserTable onEdit={user => modal.openEditModal(user)} />
<UserModal
isOpen={modal.isOpen}
title={isEditing ? `Edit ${modal.data?.name}` : 'New User'}
initialData={modal.data} // null = empty form; User = pre-filled
isSaving={modal.isLoading}
onSave={async (formData) => {
modal.setLoading(true);
try {
if (isEditing) {
await updateUser(modal.data!._id, formData);
toast.success('User updated');
} else {
await createUser(formData);
toast.success('User created');
}
modal.closeModal();
} catch (err) {
toast.error(err instanceof Error ? err.message : 'Failed');
} finally {
modal.setLoading(false);
}
}}
onClose={modal.closeModal}
/>
</>
);
}