Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как React рендерит страницу
Рендеринг в React — это процесс преобразования JSX компонентов в HTML элементы, которые видит пользователь в браузере. Процесс состоит из нескольких этапов.
Этапы рендеринга
1. Парсинг JSX
Babel переводит JSX в вызовы React.createElement():
// JSX
<Component name="John" age={30} />
// Превращается в
React.createElement(Component, { name: 'John', age: 30 })
2. Создание Virtual DOM (VDOM)
React создаёт виртуальное представление дерева компонентов:
const vdom = React.createElement('div', null,
React.createElement('h1', null, 'Заголовок'),
React.createElement('p', null, 'Текст')
);
3. Reconciliation (сравнение)
React сравнивает новое VDOM со старым и находит различия:
// Старое VDOM
<div>
<p>Старый текст</p>
</div>
// Новое VDOM
<div>
<p>Новый текст</p> // Изменился
<span>Новый элемент</span> // Добавился
</div>
// React вычисляет только изменения
4. Коммит (применение изменений)
React применяет изменения к реальному DOM:
// React обновляет:
// 1. Текст в <p>
// 2. Добавляет <span>
// 3. Оставляет <div> без изменений
Жизненный цикл рендеринга
function App() {
// 1. RENDER PHASE (чистый, без побочных эффектов)
const [count, setCount] = useState(0);
// 2. Вычисление VDOM
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
// 3. COMMIT PHASE (с побочными эффектами)
// useEffect выполняется здесь
}
Fiber архитектура (React 16+)
React использует Fiber для разбиения рендеринга на небольшие куски:
// Раньше (React 15):
// Синхронный рендеринг — весь Stack за раз
// Проблема: браузер зависает при больших обновлениях
// Теперь (React 16+):
// Асинхронный рендеринг через Fiber
// Можно прервать и продолжить позже
// Приоритеты: пользовательское взаимодействие выше
Пример рендеринга
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Монтирование или обновление');
return () => console.log('Очистка');
}, [count]);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
Первый рендеринг:
- count = 0
- Возвращает:
<div><h1>0</h1><button>+</button></div> - Коммит в DOM
- useEffect выполняется
После клика:
- setCount(1) → плановый рендеринг
- count = 1
- Возвращает:
<div><h1>1</h1><button>+</button></div> - Сравнение VDOM → изменилась только строка "0" → "1"
- Обновление DOM (только текст)
- Cleanup из useEffect предыдущего
- useEffect нового рендеринга
Оптимизации рендеринга
1. React.memo — мемоизация компонентов
const Item = React.memo(({ name }) => {
console.log('Рендер Item');
return <li>{name}</li>;
});
function List() {
const [count, setCount] = useState(0);
return (
<div>
<Item name="A" />
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
);
}
// Item не перерендерится при изменении count
2. useMemo — мемоизация значений
function Component() {
const [count, setCount] = useState(0);
const expensive = useMemo(() => {
console.log('Вычисляю');
return count * 2;
}, [count]);
return <div>{expensive}</div>;
}
// Вычисляет только когда count меняется
3. useCallback — мемоизация функций
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
return <Child onClick={handleClick} />;
}
// handleClick пересоздаётся только при изменении count
Key в списках
// Без key — React переиспользует элементы
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo.text}</li> // Плохо!
))}
</ul>
);
}
// С key — React отслеживает элементы правильно
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li> // Хорошо!
))}
</ul>
);
}
Батчинг обновлений (React 18+)
function handleClick() {
// React группирует оба обновления в один рендеринг
setCount(c => c + 1);
setName('New');
// Один VDOM сравнение
// Один коммит
}
// Раньше нужно было оборачивать в flushSync для немедленного
import { flushSync } from 'react-dom';
function handleClick() {
flushSync(() => setCount(c => c + 1));
// Немедленный рендеринг
}
Краткая схема
Компонент функция → Пропсы/State → VDOM
↓
Сравнение с предыдущим
↓
Найти различия (diff)
↓
Обновить реальный DOM
↓
Выполнить useEffect
↓
Пользователь видит
Производительность
// Профилирование в Chrome DevTools
// React DevTools → Profiler
// Видно какие компоненты рендерились и почему
// Избегай:
- Создания новых объектов в render
- Анонимных функций в пропсах
- Больших списков без key
- Глубоких вложенностей компонентов
Вывод
Рендеринг в React:
- Создаёт VDOM на основе пропсов/состояния
- Сравнивает с предыдущим VDOM
- Находит различия
- Обновляет реальный DOM
- Запускает побочные эффекты (useEffect)
Это очень эффективно благодаря Virtual DOM, Fiber архитектуре и оптимизациям.