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

Как работает Reconciliation?

1.8 Middle🔥 191 комментариев
#React#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Как работает Reconciliation

Reconciliation (согласование) - это процесс, который React использует для определения того, какие части DOM нужно обновить. Это сердце React, которое делает его быстрым.

Проблема, которую решает Reconciliation

Когда состояние компонента меняется, React должен:

  1. Понять, что изменилось
  2. Найти соответствующие элементы DOM
  3. Обновить только нужные элементы

Наивный подход был бы обновить весь DOM, но это очень медленно:

// Плохо: переrendering весь список
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
// Если добавить одного пользователя, React перерендер весь список

Как работает Reconciliation

Шаг 1: Virtual DOM Render фаза создает новое "виртуальное представление" UI:

const prevVDOM = {
  type: 'div',
  children: [{ type: 'p', text: 'Hello' }]
};

const nextVDOM = {
  type: 'div',
  children: [
    { type: 'p', text: 'Hello' },
    { type: 'p', text: 'World' } // новый элемент
  ]
};

Шаг 2: Diff алгоритм React сравнивает prevVDOM и nextVDOM:

// Было:
render() { return <div><Child a={1} /></div> }

// Стало:
render() { return <div><Child a={2} /></div> }

// React видит: props 'a' изменился с 1 на 2
// Нужно обновить Child компонент

Шаг 3: Commit фаза Render применяет изменения к реальному DOM:

// React обновляет только изменившиеся элементы
dom.textContent = 'Updated text'; // только это
// остальной DOM не трогает

Пример Reconciliation в действии

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <StaticComponent />
    </div>
  );
}

function StaticComponent() {
  return <div>This never changes</div>;
}

Когда нажимаем кнопку:

  1. setCount вызывает re-render
  2. React создает новый VDOM
  3. Сравнивает: <p>Count: 0</p> -> <p>Count: 1</p> (изменилось)
  4. StaticComponent не изменился
  5. Обновляет только текст в <p>

Ключи (Keys) - критически важны

Когда у вас есть список элементов, ВСЕГДА используйте keys:

// Плохо: без keys
{users.map(user => (
  <li>{user.name}</li>
))}

// Хорошо: с keys
{users.map(user => (
  <li key={user.id}>{user.name}</li>
))}

Без keys React может спутать элементы:

// Было: [Alice, Bob, Charlie]
// Стало: [Alice, Bob, Charlie, Dave]

// Без keys React может подумать:
// - Alice -> Alice (ok)
// - Bob -> Bob (ok)
// - Charlie -> Charlie (ok)
// + Dave (новый)
// ВСЕ элементы пересчитываются

// С keys React знает:
// - key=1 (Alice) -> key=1 (Alice) (не меняется)
// - key=2 (Bob) -> key=2 (Bob) (не меняется)
// - key=3 (Charlie) -> key=3 (Charlie) (не меняется)
// + key=4 (Dave) (просто добавить)
// Обновляется только новый элемент

Reconciliation алгоритм (упрощенно)

Ract использует эвристики для быстрого сравнения:

// Эвристика 1: Разные типы элементов
if (prevElement.type !== nextElement.type) {
  // Выкинуть старый элемент, создать новый
  destroy(prevElement);
  create(nextElement);
}

// Эвристика 2: Одинаковый тип, разные props
if (prevElement.props !== nextElement.props) {
  // Обновить props
  updateProps(element, nextElement.props);
}

// Эвристика 3: Одинаковые элементы
// Recurse на children с keys

Когда Reconciliation может быть неэффективным

Проблема: inline функции как children

// Плохо: новая функция на каждый render
<List items={items} onRender={(item) => <Item data={item} />} />

// Хорошо: одна функция
const renderItem = (item) => <Item data={item} />;
<List items={items} onRender={renderItem} />

Проблема: new object на каждый render

// Плохо:
const style = { color: 'red' }; // новый объект каждый раз!
<div style={style}></div>

// Хорошо:
const style = useMemo(() => ({ color: 'red' }), []);
<div style={style}></div>

Оптимизация Reconciliation

React.memo - мемоизирует компонент:

const Item = React.memo(({ data }) => {
  return <div>{data.name}</div>;
});

// Item не будет переrenderен, если props не изменились

useMemo - мемоизирует вычисления:

const expensiveValue = useMemo(
  () => computeExpensive(data),
  [data] // зависимости
);

useCallback - мемоизирует функции:

const handleClick = useCallback(() => {
  setCount(count + 1);
}, [count]);

// Функция не создается заново, если count не изменился

Reconciliation vs Concurrent Rendering

В React 18+ reconciliation может быть прерван для более приоритетных обновлений:

// Высокий приоритет: user input
flushSync(() => setInputValue(e.target.value));

// Низкий приоритет: фоновое обновление
startTransition(() => {
  setSearchResults(data);
});

Заключение

Reconciliation - это магия React, которая:

  1. Быстро определяет, что изменилось
  2. Минимизирует DOM обновления
  3. Использует эвристики для эффективного сравнения
  4. Позволяет разработчикам писать код как будто компонент полностью переrenderится
  5. На самом деле обновляет только нужные части

Понимание Reconciliation помогает писать более производительный React код и избегать типичных ошибок.