Перейти к основному содержимому

@form-guardian/react

React хуки и компоненты для автосохранения форм. Построено поверх @form-guardian/dom.

Установка

npm install @form-guardian/react

Peer зависимости:

  • react: ^16.8.0 || ^17.0.0 || ^18.0.0

useFormAutosave(formId, options)

Основной React хук для автосохранения форм.

⚠️ Уведомление о стабильности

useFormAutosave в настоящее время нестабилен и может иметь проблемы в определенных случаях использования. Для production приложений рекомендуется использовать attachFormAutosave из @form-guardian/dom напрямую, что более стабильно и надежно.

Импорт:

import { useFormAutosave } from '@form-guardian/react';

Параметры:

  • formId (string, обязательный) - Уникальный идентификатор формы
  • options (FormAutosaveOptions, опциональный) - Опции конфигурации

Возвращает: UseFormAutosaveReturn

Пример:

import { useFormAutosave } from '@form-guardian/react';

function MyForm() {
const {
formRef,
hasDraft,
draftTimestamp,
restoreDraft,
clearDraft,
getDraftValues,
restoreValues,
saveValues,
} = useFormAutosave('my-form', {
autoRestore: true,
debounceMs: 300,
batchSaveInterval: 5000, // Сохранение пакетами каждые 5 секунд
onBeforeSave: async (values) => {
console.log('Собираемся сохранить:', values);
},
onAfterSave: async (values) => {
console.log('Успешно сохранено:', values);
},
});

return (
<form ref={formRef}>
{hasDraft && (
<div className="draft-banner">
Черновик сохранен: {new Date(draftTimestamp).toLocaleString()}
</div>
)}
{/* поля формы */}
</form>
);
}

UseFormAutosaveReturn

Объект, возвращаемый хуком useFormAutosave().

Свойства

formRef: RefObject<HTMLFormElement>

Ref для привязки к элементу формы. Обязательно.

<form ref={formRef}>...</form>

hasDraft: boolean

Существует ли черновик для этой формы.

{hasDraft && <div>У вас есть несохраненные изменения</div>}

draftTimestamp: number | null

Временная метка последнего обновления черновика, или null если черновика нет.

{draftTimestamp && (
<div>Последнее сохранение: {new Date(draftTimestamp).toLocaleString()}</div>
)}

Методы

restoreDraft(): Promise<void>

Вручную восстановить черновик в форму. Обычно не нужно при autoRestore: true.

<button onClick={() => restoreDraft()}>Восстановить черновик</button>

clearDraft(): Promise<void>

Очистить черновик из хранилища.

const handleSubmit = async (e) => {
e.preventDefault();
await clearDraft();
// Отправить форму...
};

getDraftValues(): Promise<T | null>

Получить значения черновика как объект без восстановления в форму.

const values = await getDraftValues();
console.log(values); // { name: 'Иван', email: 'ivan@example.com' }

restoreValues(setValue, getValues): Promise<void>

Восстановить значения для контролируемых компонентов (React Hook Form, Formik и т.д.).

// Пример React Hook Form
const { setValue, getValues } = useForm();

const handleRestore = async () => {
await restoreValues(setValue, getValues);
};

saveValues(): Promise<void>

Вручную сохранить текущие значения формы. Полезно для контролируемых форм.

<button onClick={() => saveValues()}>Сохранить черновик</button>

useDraftStatus(formId, options)

Легковесный хук для получения статуса черновика без взаимодействия с DOM. Идеален для отображения индикаторов черновика вне компонента формы.

Импорт:

import { useDraftStatus } from '@form-guardian/react';

Параметры:

  • formId (string, обязательный) - Уникальный идентификатор формы
  • options (UseDraftStatusOptions, опциональный) - Опции конфигурации

Возвращает: UseDraftStatusResult

Пример:

import { useDraftStatus } from '@form-guardian/react';

function DraftIndicator() {
const {
hasDraft,
updatedAt,
isExpired,
isChecking,
refresh,
clear
} = useDraftStatus('my-form', {
ttl: { days: 7 },
});

if (isChecking) return <div>Проверка...</div>;
if (!hasDraft) return null;
if (isExpired) return <div>Черновик истек</div>;

return (
<div>
Черновик сохранен: {new Date(updatedAt).toLocaleString()}
<button onClick={clear}>Очистить</button>
<button onClick={refresh}>Обновить</button>
</div>
);
}

UseDraftStatusResult

Объект, возвращаемый хуком useDraftStatus().

Свойства

hasDraft: boolean

Существует ли черновик.

isExpired: boolean

Истек ли черновик (на основе TTL).

updatedAt: number | null

Временная метка последнего обновления черновика.

isChecking: boolean

Проверяется ли статус в данный момент.

Методы

refresh(): Promise<void>

Вручную обновить статус черновика из хранилища.

clear(): Promise<void>

Очистить черновик из хранилища.

Примеры использования

Неконтролируемая форма

import { useFormAutosave } from '@form-guardian/react';

function ContactForm() {
const { formRef, hasDraft, clearDraft } = useFormAutosave('contact-form', {
autoRestore: true,
debounceMs: 500,
});

const handleSubmit = async (e) => {
e.preventDefault();
await clearDraft();
// Отправить форму...
};

return (
<form ref={formRef} onSubmit={handleSubmit}>
{hasDraft && <div className="alert">Обнаружены несохраненные изменения</div>}
<input name="name" placeholder="Имя" />
<input name="email" type="email" placeholder="Email" />
<button type="submit">Отправить</button>
</form>
);
}

React Hook Form (Контролируемая)

import { useForm } from 'react-hook-form';
import { useFormAutosave } from '@form-guardian/react';
import { useEffect } from 'react';

function MyForm() {
const { register, handleSubmit, setValue, getValues, watch } = useForm();

const { formRef, restoreValues, clearDraft, saveValues } = useFormAutosave(
'my-form',
{
autoRestore: false, // Ручное восстановление для контролируемых форм
debounceMs: 300,
}
);

// Восстановить черновик при монтировании
useEffect(() => {
restoreValues(setValue, getValues);
}, []);

// Автосохранение при изменении полей
useEffect(() => {
const subscription = watch(() => {
saveValues();
});
return () => subscription.unsubscribe();
}, [watch]);

const onSubmit = async (data) => {
await clearDraft();
// Отправить данные...
};

return (
<form ref={formRef} onSubmit={handleSubmit(onSubmit)}>
<input {...register('name')} />
<input {...register('email')} />
<button type="submit">Отправить</button>
</form>
);
}

Индикатор статуса черновика (отдельный компонент)

import { useDraftStatus } from '@form-guardian/react';

function Header() {
const { hasDraft, updatedAt } = useDraftStatus('contact-form');

return (
<header>
<h1>Мое приложение</h1>
{hasDraft && (
<div className="draft-badge">
📝 Несохраненный черновик от {new Date(updatedAt).toLocaleTimeString()}
</div>
)}
</header>
);
}

Связанные материалы