@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}
      />
    </>
  );
}