TL;DR: Для uncontrolled компонентов, где значение input нужно только при сабмите формы, useRef предпочтительнее useState, так как избегает лишних ререндеров. Но для валидации или динамического UI лучше подходит useState.
Введение: проблема лишних ререндеров
Каждый React-разработчик сталкивался с дилеммой: использовать ли useState или useRef для работы с input элементами. Особенно актуален этот вопрос в формах, где значения полей нужны только при сабмите.
Основная проблема useState - триггеринг ререндера при каждом изменении значения. В больших формах это может привести к performance issues, особенно если компонент сложный и содержит тяжелые вычисления.
Базовые примеры реализации
Рассмотрим оба подхода на практике:
// Вариант с useState (controlled component)
function FormWithState() {
const [value, setValue] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submitted value:', value);
};
return (
<form onSubmit={handleSubmit}>
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
);
}
// Вариант с useRef (uncontrolled component)
function FormWithRef() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submitted value:', inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
Когда что выбирать?
Преимущества useRef:
- Нет лишних ререндеров - компонент не обновляется при каждом изменении input
- Лучшая производительность для больших форм
- Проще интеграция с нативными DOM API
Когда все же нужен useState:
- Валидация в реальном времени - нужно показывать ошибки при вводе
- Динамический UI - когда интерфейс меняется в зависимости от ввода
- Сброс значений - с useState проще реализовать reset формы
Advanced паттерны
Для сложных сценариев можно комбинировать оба подхода:
function SmartForm() {
const inputRef = useRef(null);
const [isValid, setIsValid] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
if (isValid) {
console.log('Submitted value:', inputRef.current.value);
}
};
const validate = () => {
const value = inputRef.current.value;
setIsValid(value.length > 5); // Пример валидации
};
return (
<form onSubmit={handleSubmit}>
<input
ref={inputRef}
onChange={validate}
/>
{!isValid && <small>Минимум 6 символов</small>}
<button type="submit" disabled={!isValid}>
Submit
</button>
</form>
);
}
Перформанс-метрики
Вот примерные цифры для формы с 10 input элементами:
| Метод | Ререндеры при вводе | Время обработки |
|---|---|---|
| useState | 10 | ~15ms |
| useRef | 0 | ~2ms |
Разница становится критичной в complex forms или на слабых устройствах.
Заключение
Выбор между useRef и useState для работы с input - это trade-off между производительностью и функциональностью. Для простых форм, где значения нужны только при сабмите, useRef - оптимальный выбор. Но если нужен динамический UI или валидация, useState остается предпочтительным вариантом.
Современные React-приложения часто используют гибридный подход, комбинируя оба метода для достижения баланса между производительностью и UX.
Источник: https://www.reddit.com/r/reactjs/comments/1smhyit/react_when_dealing_with_input_box/