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

Хук статуса черновика

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

Обзор

useDraftStatus предоставляет:

  • Отслеживание статуса черновика в реальном времени
  • Без манипуляций с DOM (только чтение)
  • Определение истечения срока
  • Возможность ручного обновления

Зачем нужен useDraftStatus?

В отличие от useFormAutosave, useDraftStatus:

  • ✅ Не прикрепляется к элементам DOM
  • ✅ Не сохраняет и не восстанавливает черновики
  • ✅ Только читает из хранилища
  • ✅ Идеален для индикаторов статуса, баннеров и UI компонентов

Базовое использование

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

function DraftBanner() {
const { hasDraft, updatedAt, isExpired, isChecking } = useDraftStatus('my-form');

if (isChecking) {
return <div>Проверка черновика...</div>;
}

if (!hasDraft) {
return null;
}

if (isExpired) {
return <div>Ваш черновик истек</div>;
}

return (
<div>
Черновик сохранен в {new Date(updatedAt!).toLocaleString()}
</div>
);
}

Справочник API

Параметры

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

Опции

interface UseDraftStatusOptions {
includeOrigin?: boolean; // Включить origin в ID черновика (по умолчанию: true)
storagePrefix?: string; // Префикс ключа хранилища (по умолчанию: 'fg')
ttl?: number | { // Время жизни для черновиков
days?: number;
hours?: number;
minutes?: number;
};
}

Возвращаемое значение

interface UseDraftStatusResult {
hasDraft: boolean; // Существует ли черновик
isExpired: boolean; // Истек ли черновик
updatedAt: number | null; // Временная метка черновика (если существует)
isChecking: boolean; // Проверяется ли статус
refresh: () => Promise<void>; // Вручную обновить статус
clear: () => Promise<void>; // Очистить черновик из хранилища
}

Примеры

Простой индикатор статуса

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

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

if (!hasDraft) return null;

return (
<div className="draft-indicator">
💾 Черновик сохранен {new Date(updatedAt!).toLocaleString()}
</div>
);
}

Статус с истечением срока

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

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

if (!hasDraft) {
return <div>Черновик недоступен</div>;
}

if (isExpired) {
return <div className="expired">⚠️ Черновик истек</div>;
}

return (
<div className="active">
✓ Черновик сохранен {new Date(updatedAt!).toLocaleString()}
</div>
);
}

Ручное обновление

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

function DraftStatusWithRefresh() {
const { hasDraft, updatedAt, isChecking, refresh } = useDraftStatus('my-form');

return (
<div>
{isChecking ? (
<span>Проверка...</span>
) : hasDraft ? (
<span>Черновик: {new Date(updatedAt!).toLocaleString()}</span>
) : (
<span>Нет черновика</span>
)}
<button onClick={() => refresh()}>Обновить</button>
</div>
);
}

Очистка черновика

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

function DraftControls() {
const { hasDraft, updatedAt, clear } = useDraftStatus('my-form');

const handleClear = async () => {
await clear();
// Черновик теперь очищен
// hasDraft будет false при следующем рендере
};

return (
<div>
{hasDraft && (
<div>
<span>Черновик: {new Date(updatedAt!).toLocaleString()}</span>
<button onClick={handleClear}>Очистить черновик</button>
</div>
)}
</div>
);
}

Случаи использования

1. Баннер черновика

Показать баннер, когда существует черновик:

function DraftBanner() {
const { hasDraft, updatedAt } = useDraftStatus('checkout-form');

if (!hasDraft) return null;

return (
<div className="banner">
У вас есть несохраненный черновик от {new Date(updatedAt!).toLocaleString()}
</div>
);
}

2. Индикатор в навигации

Показать статус черновика в навигации:

function Navigation() {
const { hasDraft } = useDraftStatus('contact-form');

return (
<nav>
<Link href="/contact">Контакты {hasDraft && '💾'}</Link>
</nav>
);
}

3. Статус в заголовке формы

Показать статус в заголовке формы:

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

return (
<header>
<h1>Моя форма</h1>
{hasDraft && (
<div className="status">
{isExpired ? (
<span className="expired">Черновик истек</span>
) : (
<span>Последнее сохранение: {new Date(updatedAt!).toLocaleString()}</span>
)}
</div>
)}
</header>
);
}

4. Несколько форм

Отслеживание статуса для нескольких форм:

function MultiFormStatus() {
const contactStatus = useDraftStatus('contact-form');
const checkoutStatus = useDraftStatus('checkout-form');

return (
<div>
<div>Контакты: {contactStatus.hasDraft ? '💾' : '✗'}</div>
<div>Оформление: {checkoutStatus.hasDraft ? '💾' : '✗'}</div>
</div>
);
}

Лучшие практики

1. Согласованная конфигурация

При использовании с useFormAutosave, сопоставьте конфигурацию:

// useFormAutosave
const { formRef } = useFormAutosave('my-form', {
includeOrigin: true,
storagePrefix: 'fg',
ttl: { days: 7 },
});

// useDraftStatus (должны совпадать)
const { hasDraft } = useDraftStatus('my-form', {
includeOrigin: true, // Должно совпадать
storagePrefix: 'fg', // Должно совпадать
ttl: { days: 7 }, // Должно совпадать
});

2. Обработка состояния загрузки

const { hasDraft, isChecking } = useDraftStatus('my-form');

if (isChecking) {
return <Skeleton />; // Показать состояние загрузки
}

// Отрисовать фактический контент

Производительность

  • Легковесный - Без манипуляций с DOM, только чтение из хранилища
  • Эффективный - Читает только когда нужно
  • Кэшированный - Статус кэшируется до обновления или широковещательного обновления
  • Безопасный для SSR - Возвращает безопасные значения по умолчанию на сервере

Следующие шаги