Быстрый старт
Создайте простую контактную форму за 5 минут.
Шаг 1: Создание компонентов для полей
ReFormer использует ваши собственные компоненты для отображения полей.
Базовые компоненты
src/components/ui/Input.tsx
import * as React from 'react';
interface InputProps {
value?: string;
onChange?: (value: string) => void;
onBlur?: () => void;
placeholder?: string;
disabled?: boolean;
}
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ value, onChange, onBlur, placeholder, disabled }, ref) => (
<input
ref={ref}
type="text"
value={value ?? ''}
onChange={(e) => onChange?.(e.target.value)}
onBlur={onBlur}
placeholder={placeholder}
disabled={disabled}
className="border rounded px-3 py-2 w-full"
/>
)
);
src/components/ui/Textarea.tsx
import * as React from 'react';
interface TextareaProps {
value?: string;
onChange?: (value: string) => void;
onBlur?: () => void;
placeholder?: string;
disabled?: boolean;
}
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ value, onChange, onBlur, placeholder, disabled }, ref) => (
<textarea
ref={ref}
value={value ?? ''}
onChange={(e) => onChange?.(e.target.value)}
onBlur={onBlur}
placeholder={placeholder}
disabled={disabled}
rows={4}
className="border rounded px-3 py-2 w-full"
/>
)
);
Универсальный компонент FormField
Зачем FormField?
FormField автоматически:
- Отображает label из
componentProps - Связывает значение с формой
- Вызывает
markAsTouched()при blur - Показывает ошибки валидации
Данный компонент нужен не только для того что бы унифицировать работу с полями формы но и оптимизировать рендер формы.
src/components/ui/FormField.tsx
import * as React from 'react';
import { useFormControl, type FieldNode } from '@reformer/core';
interface FormFieldProps {
control: FieldNode<any>;
className?: string;
}
export const FormField: React.FC<FormFieldProps> = ({ control, className }) => {
const { value, errors, disabled, shouldShowError, componentProps } = useFormControl(control);
const Component = control.component;
return (
<div className={className}>
{componentProps.label && (
<label className="block mb-1 text-sm font-medium">{componentProps.label}</label>
)}
<Component
{...componentProps}
value={value ?? ''}
onChange={(e: unknown) => {
const newValue = (e as { target?: { value?: unknown } })?.target?.value ?? e;
control.setValue(newValue);
}}
onBlur={() => control.markAsTouched()}
disabled={disabled}
/>
{shouldShowError && (
<span className="text-red-500 text-sm mt-1 block">{errors[0]?.message}</span>
)}
</div>
);
};
Шаг 2: Описание интерфейса формы
src/forms/contact-form.type.ts
type ContactFormType = {
name: string;
email: string;
message: string;
};
Шаг 3: Создание описания формы
Ключевые моменты
createForm<T>— фабричная функция с автоматической типизациейcomponent— React-компонент для отображения поляcomponentProps— пропсы для компонента (label, placeholder и т.д.)validation— декларативная схема валидации
src/forms/contact-form.ts
import { createForm } from '@reformer/core';
import { required, email, minLength } from '@reformer/core/validators';
import { Input } from '@/components/ui/Input';
import { Textarea } from '@/components/ui/Textarea';
import { ContactFormType } from '@/forms/contact-form.type';
export const createContactForm = () =>
createForm<ContactFormType>({
form: {
name: { value: '', component: Input, componentProps: { label: 'Имя' } },
email: { value: '', component: Input, componentProps: { label: 'Email' } },
message: { value: '', component: Textarea, componentProps: { label: 'Сообщение' } },
},
validation: (path) => {
required(path.name);
minLength(path.name, 2);
required(path.email);
email(path.email);
required(path.message);
minLength(path.message, 10);
},
});
Шаг 4: Создание компонента формы
src/components/ContactForm.tsx
import { useMemo } from 'react';
import { createContactForm } from '@/forms/contact-form';
import { FormField } from '@/components/ui/FormField';
export function ContactForm() {
const form = useMemo(() => createContactForm(), []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
form.markAsTouched();
await form.validate();
if (form.valid.value) {
console.log('Отправка:', form.value.value);
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-md">
<FormField control={form.name} />
<FormField control={form.email} />
<FormField control={form.message} />
<button
type="submit"
disabled={form.invalid.value}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
Отправить
</button>
</form>
);
}
Результат
Вы создали форму с:
- ✅ Типобезопасностью TypeScript
- ✅ Декларативной валидацией
- ✅ Автоматическим отображением ошибок
- ✅ Чистым и минимальным кодом
Следующие шаги
- Основные концепции — узнайте больше о Nodes
- Валидация — все встроенные валидаторы
- Behaviors — вычисляемые поля и условная логика