Работа с различными типами input элементов

В Preact управление формами и элементами ввода строится на тех же принципах, что и в React, однако с учётом лёгкой и оптимизированной архитектуры Preact. Основной механизм взаимодействия с input заключается в использовании состояния компонентов и обработчиков событий.


Контролируемые и неконтролируемые компоненты

Контролируемый компонент — это элемент формы, значение которого полностью управляется состоянием компонента. Для input это достигается через свойство value:

import { h } from 'preact';
import { useState } from 'preact/hooks';

function ControlledInput() {
    const [value, setValue] = useState('');

    const handleChange = (e) => setValue(e.target.value);

    return <input type="text" value={value} onIn put={handleChange} />;
}
  • onInput используется вместо стандартного onChange, так как в Preact onChange срабатывает только при потере фокуса.
  • Значение value синхронизировано с состоянием value.

Неконтролируемый компонент хранит состояние внутри самого DOM-элемента. С ним удобно работать через ref:

import { h } from 'preact';
import { useRef } from 'preact/hooks';

function UncontrolledInput() {
    const inputRef = useRef();

    const handleClick = () => {
        alert(inputRef.current.value);
    };

    return (
        <div>
            <input type="text" ref={inputRef} />
            <button onCl ick={handleClick}>Показать значение</button>
        </div>
    );
}

Текстовые поля и textarea

Для текстовых полей (type="text", textarea) контролируемый подход применяется аналогично:

function TextAreaExample() {
    const [text, setText] = useState('');

    return (
        <textarea
            value={text}
            onIn put={(e) => setText(e.target.value)}
        />
    );
}
  • textarea использует value и onInput точно так же, как input.
  • В Preact рекомендуется всегда использовать onInput для мгновенного обновления состояния.

Чекбоксы и радио кнопки

Чекбоксы управляются свойством checked:

function CheckboxExample() {
    const [checked, setChecked] = useState(false);

    return (
        <input
            type="checkbox"
            checked={checked}
            onIn put={(e) => setChecked(e.target.checked)}
        />
    );
}

Радио кнопки используют ту же концепцию:

function RadioExample() {
    const [selected, setSelected] = useState('option1');

    return (
        <div>
            <label>
                <input
                    type="radio"
                    value="option1"
                    checked={selected === 'option1'}
                    onIn put={(e) => setSelected(e.target.value)}
                />
                Опция 1
            </label>
            <label>
                <input
                    type="radio"
                    value="option2"
                    checked={selected === 'option2'}
                    onIn put={(e) => setSelected(e.target.value)}
                />
                Опция 2
            </label>
        </div>
    );
}
  • checked указывает текущее состояние выбора.
  • Для группы радио кнопок состояние хранится в одном useState.

Селекты (select)

Для <select> ключевое свойство — value. Контролируемый компонент работает так:

function SelectExample() {
    const [option, setOption] = useState('apple');

    return (
        <select value={option} onIn put={(e) => setOption(e.target.value)}>
            <option value="apple">Яблоко</option>
            <option value="banana">Банан</option>
            <option value="cherry">Вишня</option>
        </select>
    );
}
  • Множественный выбор управляется массивом значений и проверкой selected для каждой опции.
  • onInput позволяет мгновенно синхронизировать состояние с выбором пользователя.

Работа с файловыми input

Элемент <input type="file"> не может быть полностью контролируемым через value из-за ограничений безопасности. Работа ведётся через ref:

function FileInputExample() {
    const fileRef = useRef();

    const handleFiles = () => {
        const files = fileRef.current.files;
        console.log(files);
    };

    return (
        <div>
            <input type="file" ref={fileRef} multiple />
            <button onCl ick={handleFiles}>Загрузить</button>
        </div>
    );
}
  • files содержит массив выбранных файлов.
  • Для нескольких файлов используется атрибут multiple.

Управление различными типами input в одной форме

Часто в форме присутствует комбинация текстовых полей, чекбоксов, радио и селектов. Стандартная практика — хранить единое состояние формы как объект:

function FormExample() {
    const [formData, setFormData] = useState({
        name: '',
        agree: false,
        fruit: 'apple',
    });

    const handleChange = (e) => {
        const { type, name, value, checked } = e.target;
        setFormData({
            ...formData,
            [name]: type === 'checkbox' ? checked : value,
        });
    };

    return (
        <form>
            <input
                type="text"
                name="name"
                value={formData.name}
                onIn put={handleChange}
            />
            <input
                type="checkbox"
                name="agree"
                checked={formData.agree}
                onIn put={handleChange}
            />
            <select
                name="fruit"
                value={formData.fruit}
                onIn put={handleChange}
            >
                <option value="apple">Яблоко</option>
                <option value="banana">Банан</option>
            </select>
        </form>
    );
}
  • Использование одного обработчика упрощает синхронизацию состояния.
  • Поддержка всех типов input достигается проверкой type и выбора между checked и value.

Динамическое управление input

Preact позволяет создавать формы, где поля добавляются динамически. Например, массив полей с текстовыми значениями:

function DynamicInputs() {
    const [items, setItems] = useState(['']);

    const handleChange = (index, value) => {
        const newItems = [...items];
        newItems[index] = value;
        setItems(newItems);
    };

    const addItem = () => setItems([...items, '']);

    return (
        <div>
            {items.map((item, i) => (
                <input
                    key={i}
                    value={item}
                    onIn put={(e) => handleChange(i, e.target.value)}
                />
            ))}
            <button onCl ick={addItem}>Добавить поле</button>
        </div>
    );
}
  • Состояние хранится в массиве, каждый элемент синхронизирован с соответствующим input.
  • Ключи (key) важны для корректной работы Preact при рендеринге списка элементов.

Особенности Preact при работе с input

  • onInput предпочтительнее onChange для мгновенного получения значения.
  • Контролируемые компоненты позволяют полностью управлять состоянием формы и реализовать валидацию.
  • Использование ref необходимо для файловых input и неконтролируемых случаев.
  • Совмещение разных типов input удобно через единый объект состояния формы.