Что изменится в реальном DOM при клике в React
Дан блок кода:
import React, { useState } from 'react';
function SimpleButton(props) {
const [txt, setTxt] = useState(props.text || 'a');
const changeText = () => {
setTxt(txt + txt);
};
return (
<button onClick={changeText}>
{txt}
</button>
);
}
Что произойдёт в реальном DOM при клике на кнопку в данном React-компоненте?
Компонент будет вызываться так:
<SimpleButton />
Что произойдёт при клике пошагово
Исходный компонент:
import React, { useState } from 'react';
function SimpleButton(props) {
const [txt, setTxt] = useState(props.text || 'a');
const changeText = () => {
setTxt(txt + txt);
};
return (
<button onClick={changeText}>
{txt}
</button>
);
}
Компонент вызывается как <SimpleButton />, значит props.text отсутствует и начальное состояние будет 'a'.
- Первый рендер создаёт DOM-узел кнопки и текстовый узел со значением
aвнутри неё. - Клик вызывает обработчик
changeText, который вызываетsetTxt(txt + txt)и тем самым ставит обновление state в очередь. - Обновление state автоматически триггерит повторный рендер компонента (React снова вызывает функцию компонента, чтобы понять, что должно быть на экране).
- На повторном рендере результат становится эквивалентен
<button>aa</button>, потому чтоtxtбудет'aa'на следующем рендере. - В commit-фазе React применит минимальные изменения к реальному DOM: DOM-узел
buttonостанется тем же, а текстовый узел внутри изменится сaнаaa.
Схема “триггер → рендер → commit”:
Клик
↓
setTxt(...) ставит обновление state в очередь
↓
(Trigger) React решает, что нужен ререндер
↓
(Render) React снова вызывает SimpleButton()
↓
(Diff) Находит отличие: изменился только {txt}
↓
(Commit) Меняет текстовый узел в DOM (a → aa)
Ключевой факт: “рендер” в React — это вызов функций компонентов и вычисление результата, а непосредственные изменения DOM происходят на стадии commit.
Почему кнопка не пересоздаётся
При обновлении state React сначала строит новое описание UI и сравнивает его с предыдущим, чтобы понять, что изменилось.
Если тип элемента и его положение в дереве совпадают (в обоих рендерах возвращается button на том же месте), React сохраняет существующий DOM-узел и обновляет только то, что отличается.
В данном компоненте отличается только значение {txt}, поэтому достаточно обновить текст, а не удалять и создавать button заново.
Пример “до/после” на уровне результата рендера:
// До клика:
<button>a</button>
// После клика:
<button>aa</button>
button, то div) — тогда React будет вынужден заменить узел целиком.Что с onClick и почему “атрибут” не меняется
В JSX запись onClick={changeText} выглядит как “атрибут”, но React использует собственную систему событий и делегирование, чтобы эффективно обрабатывать события.
В реальном DOM это обычно означает, что на каждом button не появляется/не обновляется “HTML-атрибут onclick”, а обработка кликов идёт через общий слушатель на корневом контейнере и внутреннее сопоставление “где кликнули” → “какой обработчик вызвать”.
Поэтому при клике в рассматриваемом примере нет необходимости менять DOM-атрибут onClick; достаточно обновить state и текст.
document), что является частью реализации делегирования событий.Дополнительный важный нюанс про state в обработчике:
- Вызов
setTxt(txt + txt)использует значениеtxt, которое было актуально на момент выполнения обработчика, а само новое значение будет доступно со следующего рендера. - Если в одном и том же событии планируется несколько обновлений, то корректнее вычислять новое состояние через функцию-обновитель.
Вариант с updater-функцией (стабильнее при нескольких обновлениях и батчинге):
const changeText = () => {
setTxt(prev => prev + prev);
};
React также может группировать несколько обновлений состояния и обновляет экран после завершения обработчиков событий, чтобы не делать лишние промежуточные перерисовки.
Итого: при клике setTxt запускает повторный рендер, и в реальном DOM сохраняется тот же узел button, но обновляется его текст (например, a → aa); обработчик onClick как HTML-атрибут обычно не переустанавливается, потому что React использует делегирование событий и синтетическую систему событий.