Skip to main content

useFormControl()

React-хук для подписки на состояние формы (FormControl или FormArray).

Обеспечивает реактивную связь между состоянием формы и React-компонентами. Использует useSyncExternalStore для оптимальной интеграции с React 18+ и Concurrent Mode.

Основные возможности​

  • Автоматическая подписка на все сигналы контрола
  • Оптимизация ре-рендеров - компонент обновляется только при реальных изменениях
  • Поддержка SSR через useSyncExternalStore
  • Типобезопасность - возвращаемый тип зависит от типа контрола

Когда использовать​

Используйте useFormControl когда компоненту нужен доступ к нескольким свойствам состояния (value, issues, touched и т.д.).

Для подписки только на значение используйте useFormControlValue - это предотвратит лишние ре-рендеры при изменении других свойств.

Type Param​

Тип значения (для FormControl) или элемента (для FormArray)

Param​

FormControl, FormArray или undefined

Examples​

import { useFormControl, useIssueMessage } from '@reformer/core/react';
import type { FormControl } from '@reformer/core';

interface TextFieldProps {
control: FormControl<string>;
label: string;
}

function TextField({ control, label }: TextFieldProps) {
const {
value,
disabled,
shouldShowError,
shouldShowIssues,
issues,
pending
} = useFormControl(control);
// Текст ошибки даёт резолвер: у правил без своего сообщения `message` пуст.
const message = useIssueMessage();

return (
<div className="field">
<label>{label}</label>

<div className="input-wrapper">
<input
type="text"
value={value}
disabled={disabled}
onChange={e => control.setValue(e.target.value)}
onBlur={() => control.markAsTouched()}
aria-invalid={shouldShowError}
/>
{pending && <Spinner />}
</div>

{shouldShowIssues && issues[0] && (
<span className="error" role="alert">
{message(issues[0])}
</span>
)}
</div>
);
}
interface CheckboxProps {
control: FormControl<boolean>;
}

function Checkbox({ control }: CheckboxProps) {
const { value, disabled, componentProps } = useFormControl(control);

return (
<label className="checkbox">
<input
type="checkbox"
checked={value}
disabled={disabled}
onChange={e => control.setValue(e.target.checked)}
/>
<span>{componentProps.label}</span>
{componentProps.hint && (
<small>{componentProps.hint}</small>
)}
</label>
);
}

// Использование
control.updateComponentProps({
label: 'Accept terms and conditions',
hint: 'Required to continue'
});
interface SelectProps {
control: FormControl<string>;
}

function Select({ control }: SelectProps) {
const { value, disabled, componentProps, shouldShowIssues, issues } = useFormControl(control);
const message = useIssueMessage(); // из '@reformer/core/react'
const options = componentProps.options as Array<{ value: string; label: string }>;

return (
<div>
<select
value={value}
disabled={disabled}
onChange={e => control.setValue(e.target.value)}
onBlur={() => control.markAsTouched()}
>
<option value="">Select...</option>
{options?.map(opt => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
{shouldShowIssues && <span className="error">{message(issues[0])}</span>}
</div>
);
}
interface Address {
street: string;
city: string;
}

interface AddressListProps {
control: FormArray<Address>;
}

function AddressList({ control }: AddressListProps) {
const { length, valid, dirty, issues } = useFormControl(control);
const message = useIssueMessage(); // из '@reformer/core/react'

const handleAdd = () => {
control.push({ street: '', city: '' });
};

const handleRemove = (index: number) => {
control.removeAt(index);
};

return (
<div className="address-list">
<div className="header">
<h3>Addresses ({length})</h3>
{dirty && <span className="badge">Modified</span>}
</div>

{issues.length > 0 && (
<div className="array-issues">
{issues.map((issue) => <p key={issue.code}>{message(issue)}</p>)}
</div>
)}

{control.map((item, index) => (
<AddressItem
key={control.keyAt(index)}
control={item}
onRemove={() => handleRemove(index)}
/>
))}

{length === 0 && (
<p className="empty">No addresses added yet</p>
)}

<button
onClick={handleAdd}
disabled={length >= 5}
>
Add Address
</button>

{!valid && (
<p className="warning">Please fix issues before submitting</p>
)}
</div>
);
}
interface FormProps {
optionalField?: FormArray<string>;
}

function Form({ optionalField }: FormProps) {
// При undefined возвращается дефолтное состояние
const { length } = useFormControl(optionalField);

if (!optionalField) {
return null;
}

return <div>Items: {length}</div>;
}

See​

Call Signature​

function useFormControl<T>(control): ArrayControlState<T>;

Defined in: platforms/react/hooks/useFormControl.ts:135

React-хук для подписки на состояние FormArray.

Type Parameters​

T​

T extends object

Тип элемента массива

Parameters​

control​

FormArray или undefined

FormArray<T> | undefined

Returns​

ArrayControlState<T>

Состояние массива ArrayControlState

Call Signature​

function useFormControl<T>(control): FieldControlState<T>;

Defined in: platforms/react/hooks/useFormControl.ts:148

React-хук для подписки на состояние FormControl.

Type Parameters​

T​

T

Тип значения поля

Parameters​

control​

FormControl<T>

FormControl для подписки

Returns​

FieldControlState<T>

Состояние поля FieldControlState