Оптимизация работы с input в React: useRef vs useState

#react#performance#hooks#forms

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:

  1. Нет лишних ререндеров - компонент не обновляется при каждом изменении input
  2. Лучшая производительность для больших форм
  3. Проще интеграция с нативными DOM API

Когда все же нужен useState:

  1. Валидация в реальном времени - нужно показывать ошибки при вводе
  2. Динамический UI - когда интерфейс меняется в зависимости от ввода
  3. Сброс значений - с 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 элементами:

МетодРерендеры при вводеВремя обработки
useState10~15ms
useRef0~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/