Автосохранение многошаговых форм
Многошаговые формы распространены в приложениях, и сохранение прогресса пользователя между шагами критически важно. Это руководство показывает, как реализовать автосохранение для многошаговых форм.
Базовая многошаговая форма
import { useState } from 'react';
import { useFormAutosave } from '@form-guardian/react';
interface FormData {
step1: { name: string; email: string };
step2: { address: string; city: string };
step3: { payment: string; terms: boolean };
}
function MultiStepForm() {
const [step, setStep] = useState(1);
const { formRef, clearDraft } = useFormAutosave('multi-step-form', {
autoRestore: true,
ttl: { days: 7 }, // Хранить черновик 7 дней
});
const handleNext = () => {
if (step < 3) {
setStep(step + 1);
}
};
const handlePrev = () => {
if (step > 1) {
setStep(step - 1);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Отправить все шаги
await clearDraft();
// Перейти на страницу успеха
};
return (
<form ref={formRef} onSubmit={handleSubmit}>
{step === 1 && (
<div>
<h2>Шаг 1: Личная информация</h2>
<input name="step1.name" placeholder="Имя" />
<input name="step1.email" type="email" placeholder="Email" />
<button type="button" onClick={handleNext}>Далее</button>
</div>
)}
{step === 2 && (
<div>
<h2>Шаг 2: Адрес</h2>
<input name="step2.address" placeholder="Адрес" />
<input name="step2.city" placeholder="Город" />
<button type="button" onClick={handlePrev}>Назад</button>
<button type="button" onClick={handleNext}>Далее</button>
</div>
)}
{step === 3 && (
<div>
<h2>Шаг 3: Оплата</h2>
<input name="step3.payment" placeholder="Способ оплаты" />
<label>
<input name="step3.terms" type="checkbox" />
Принять условия
</label>
<button type="button" onClick={handlePrev}>Назад</button>
<button type="submit">Отправить</button>
</div>
)}
</form>
);
}
Продвинутый пример с валидацией
import { useState } from 'react';
import { useFormAutosave } from '@form-guardian/react';
function AdvancedMultiStepForm() {
const [step, setStep] = useState(1);
const [errors, setErrors] = useState({});
const { formRef, clearDraft, getCurrentValues } = useFormAutosave(
'advanced-multi-step',
{
autoRestore: true,
ttl: { days: 7 },
onAfterSave: () => {
console.log('Прогресс сохранен!');
},
}
);
const validateStep = async (currentStep: number) => {
const values = await getCurrentValues();
const stepErrors = {};
if (currentStep === 1) {
if (!values['step1.name']) {
stepErrors['name'] = 'Имя обязательно';
}
if (!values['step1.email']) {
stepErrors['email'] = 'Email обязателен';
}
}
if (currentStep === 2) {
if (!values['step2.address']) {
stepErrors['address'] = 'Адрес обязателен';
}
}
setErrors(stepErrors);
return Object.keys(stepErrors).length === 0;
};
const handleNext = async () => {
const isValid = await validateStep(step);
if (isValid && step < 3) {
setStep(step + 1);
}
};
const handlePrev = () => {
if (step > 1) {
setStep(step - 1);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const isValid = await validateStep(step);
if (isValid) {
const values = await getCurrentValues();
// Отправить все данные
await submitToAPI(values);
await clearDraft();
// Перенаправить на страницу успеха
}
};
return (
<div>
{/* Индикатор прогресса */}
<div className="progress">
<div className="step" data-active={step >= 1}>1</div>
<div className="step" data-active={step >= 2}>2</div>
<div className="step" data-active={step >= 3}>3</div>
</div>
<form ref={formRef} onSubmit={handleSubmit}>
{step === 1 && (
<div>
<h2>Шаг 1: Личная информация</h2>
<input name="step1.name" placeholder="Имя" />
{errors['name'] && <span className="error">{errors['name']}</span>}
<input name="step1.email" type="email" placeholder="Email" />
{errors['email'] && <span className="error">{errors['email']}</span>}
<button type="button" onClick={handleNext}>Далее</button>
</div>
)}
{step === 2 && (
<div>
<h2>Шаг 2: Адрес</h2>
<input name="step2.address" placeholder="Адрес" />
{errors['address'] && <span className="error">{errors['address']}</span>}
<input name="step2.city" placeholder="Город" />
<button type="button" onClick={handlePrev}>Назад</button>
<button type="button" onClick={handleNext}>Далее</button>
</div>
)}
{step === 3 && (
<div>
<h2>Шаг 3: Обзор и подтверждение</h2>
<input name="step3.payment" placeholder="Способ оплаты" />
<label>
<input name="step3.terms" type="checkbox" required />
Принять условия
</label>
<button type="button" onClick={handlePrev}>Назад</button>
<button type="submit">Отправить</button>
</div>
)}
</form>
</div>
);
}
С React Hook Form
import { useForm } from 'react-hook-form';
import { useFormAutosave } from '@form-guardian/react';
import { useState, useEffect } from 'react';
function MultiStepWithRHF() {
const [step, setStep] = useState(1);
const form = useForm();
const { formRef, restoreValues, clearDraft } = useFormAutosave(
'rhf-multi-step'
);
useEffect(() => {
restoreValues(form.setValue, () => form.getValues());
}, []);
const onSubmit = async (data) => {
await submitToAPI(data);
await clearDraft();
};
return (
<form ref={formRef} onSubmit={form.handleSubmit(onSubmit)}>
{step === 1 && (
<div>
<input {...form.register('name', { required: true })} />
<input {...form.register('email', { required: true })} />
<button type="button" onClick={() => setStep(2)}>
Далее
</button>
</div>
)}
{step === 2 && (
<div>
<input {...form.register('address')} />
<input {...form.register('city')} />
<button type="button" onClick={() => setStep(1)}>
Назад
</button>
<button type="submit">О тправить</button>
</div>
)}
</form>
);
}