← Назад к вопросам

Какой механизм выполняет рендер только один раз при нескольких последовательных синхронных операциях?

2.2 Middle🔥 161 комментариев
#React

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

React и механизм "batching" обновлений состояния

В React за оптимизацию рендера при последовательных синхронных операциях отвечает механизм "batching" (группировка или пакетирование обновлений). Этот механизм автоматически группирует несколько вызовов setState() или других обновлений состояния, происходящих в одном и том же синхронном цикле событий, выполняя итоговый рендер компонента только один раз.

Как работает batching в React

Когда вы вызываете setState() несколько раз подряд в синхронном коде (например, в обработчике события или в эффекте), React не запускает перерендер после каждого вызова. Вместо этого он собирает все обновления и применяет их единовременно, после чего выполняет один ререндер.

Пример классического batching:

function Counter() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
  
  const handleClick = () => {
    // Обе операции будут сгруппированы
    setCount(count + 1);    // 1️⃣
    setText('Updated');     // 2️⃣
    // React выполнит только ОДИН ререндер после завершения функции
  };
  
  console.log('Render'); // Выведется только один раз при клике
  
  return (
    <button onClick={handleClick}>
      Count: {count}, Text: {text}
    </button>
  );
}

Эволюция batching в React

В React 17 и ранее batching работал только для обновлений, инициированных React-событиями (onClick, onChange и т.д.). Однако асинхронный код внутри этих обработчиков не покрывался batching:

// React 17 и ранее: ДВА ререндера
const handleClick = () => {
  setCount(1);                    // Первый ререндер
  setTimeout(() => {
    setCount(2);                  // Второй ререндер (без batching)
  }, 0);
};

В React 18 появился улучшенный автоматический batching, который работает во всех сценариях, включая:

  • Синхронные обработчики событий
  • Асинхронный код (setTimeout, промисы, обработчики нативных событий)
  • Методы жизненного цикла и эффекты

Пример с React 18:

// React 18: ОДИН ререндер для всех операций
const handleClick = () => {
  setCount(1);                    // ✅
  fetchData().then(() => {
    setCount(2);                  // ✅ Тоже будет сгруппировано
  });
  setTimeout(() => {
    setCount(3);                  // ✅ И это тоже будет сгруппировано
  }, 0);
};

Техническая реализация

Под капотом React использует концепцию "транзакций" обновлений:

  1. Фаза сбора обновлений: Все вызовы setState помещаются в очередь
  2. Вычисление нового состояния: React вычисляет итоговое состояние с учётом всех обновлений
  3. Сравнение Virtual DOM: React сравнивает предыдущее и новое состояние виртуального DOM
  4. Единый commit изменений: Если есть различия, React выполняет один ререндер и обновляет реальный DOM

Важные исключения и нюансы

  1. flushSync для принудительного обновления: Если вам нужно немедленное обновление DOM, можно использовать flushSync:

    import { flushSync } from 'react-dom';
    
    flushSync(() => {
      setCount(1);  // Немедленный ререндер
    });
    setCount(2);    // Второй ререндер
    
  2. Независимые обновления разных компонентов: Batching работает на уровне отдельных компонентов. Обновления разных компонентов в одном цикле событий могут группироваться независимо.

  3. Concurrent React: В React 18 batching тесно интегрирован с concurrent features, позволяя React прерывать и возобновлять рендеринг для повышения отзывчивости UI.

Практическое значение

  1. Производительность: Batching значительно снижает количество лишних рендеров и вычислений
  2. Предотвращение "мерцания" интерфейса: Избегает частичных обновлений UI
  3. Упрощение логики: Разработчикам не нужно вручную оптимизировать последовательные обновления состояния

Важный совет: При работе с React полагайтесь на автоматический batching и избегайте преждевременных оптимизаций, так как React уже включает эффективные механизмы оптимизации рендеринга. Исключения составляют особые случаи, когда требуется точный контроль над временем обновления DOM.