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

Форма

Составной компонент из LhForm + LhFormItem, предоставляющий валидацию данных, вывод ошибок, выравнивание меток и другие возможности.

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

Форма с валидацией
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'

interface FormData {
name: string
style: string
}

const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: 'Введите название произведения', trigger: 'blur' }],
style: [{ required: true, message: 'Выберите стиль живописи', trigger: 'change' }],
}

export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)

const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`Отправлено: ${formData.name} / ${formData.style}`)
}

const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}

return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="Название произведения" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="Стиль живописи" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: 'Тушь', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>Отправить</LhButton>
<LhButton onClick={handleReset}>Сбросить</LhButton>
</LhFormItem>
</LhForm>
)
}

Props компонента Form​

ПропОписаниеТипПо умолчанию
modelОбъект данных формы (обязательный)Record<string, unknown>—
rulesПравила валидации; ключи — имена полейRecord<string, LhFormRule[]>—
labelWidthШирина метокstring | number—
labelPositionПоложение меток'left' | 'right' | 'top''right'
inlineСтрочное (inline) расположениеbooleanfalse
disabledОтключить все дочерние элементыbooleanfalse
sizeРазмер дочерних элементов'large' | 'middle' | 'small'Из ConfigProvider
onSubmitНативное событие отправки (уже прошло preventDefault)(event: FormEvent) => void—

Props компонента FormItem​

ПропОписаниеТипПо умолчанию
labelТекст меткиstring—
propИмя поля (поддерживает точечный путь, соответствует ключу в model)string—
rulesПравила на уровне элемента (при совпадении имён переопределяют правила формы)LhFormRule[]—
requiredЗвёздочка обязательности (только маркер; семантика валидации задаётся в rules)booleanfalse
labelWidthПереопределяет ширину меток уровня формыstring | number—
errorMessageПользовательское сообщение об ошибкеstring—
showMessageПоказывать сообщение об ошибкеbooleantrue

LhFormRule​

ПропОписаниеТип
requiredОбязательное полеboolean
messageСообщение при ошибке валидацииstring
triggerСпособ срабатывания'blur' | 'change'
validatorПользовательская функция валидации (может возвращать Promise; асинхронная валидация корректно ожидается)(value, model) => string | undefined | Promise<string | undefined>
min / maxМинимальное / максимальное значение (число или длина)number
patternПроверка по регулярному выражениюRegExp

Методы ref формы​

LhFormInstance (предоставляется через forwardRef + useImperativeHandle):

МетодОписаниеВозвращаемое значение
validateВалидация всех полейPromise<boolean>
validateFieldВалидация отдельного поляPromise<boolean>
resetFieldsСброс всех полей к начальным значениямvoid
resetFieldСброс отдельного поляvoid
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
Асинхронная валидация

В этой библиотеке исправлен недостаток асинхронной валидации plus: в plus validateField использует Promise.resolve(!message) и не дожидается Promise асинхронного validator, поэтому асинхронная валидация всегда возвращает true. В React-версии явным образом ожидается завершение thenable, и только после этого выносится решение. Подробнее см. в Руководстве по миграции.

Регистрация полей

LhFormItem регистрирует валидатор в форме внутри useEffect и автоматически отменяет регистрацию при размонтировании. Поля не нужно заранее объявлять в rules — если поле есть в model, но отсутствует в rules, начальное значение фиксируется при регистрации.

Семантика trigger (расширение React)

Функция validateFormField в share не интерпретирует trigger; момент срабатывания определяется на уровне этой обвязки: trigger: 'blur' (по умолчанию) валидирует при потере фокуса элементом FormItem, trigger: 'change' — при изменении в области содержимого. Правила без явного trigger выполняются только при потере фокуса и вызове validate(), поэтому при вводе ошибки не появляются постоянно.

Валидация change использует новое значение цели события, а не снимок model: обновление состояния и диспетчеризация события в React происходят не в одном такте, поэтому повторное чтение model отставало бы на один такт. События change нативных элементов (input / textarea / нативный select) всплывают и перехватываются в области содержимого; пользовательские элементы не порождают нативных событий change (нажатие на пункт LhSelect даёт лишь click), поэтому валидация запускается явно через validateChange(value) из контекста FormItem с передачей нового значения.

Сброс очищает ошибки (расширение React)

Помимо возврата model к снимку начальных значений, resetFields() увеличивает внутренний resetVersion; элементы FormItem отслеживают изменение версии и очищают собственное состояние ошибки. Внешнее контролируемое состояние нужно синхронизировать самому (как setFormData(initial) в демо) — React, в отличие от реактивной цепочки Vue, не может обновить model за вас.

Стили​

import '@lh-ui/react/style/form'