Рендер и фиксация
Прежде чем ваши компоненты будут отображены на экране, они должны быть отрисованы React. Понимание этапов этого процесса поможет вам продумать, как выполняется ваш код, и объяснить его поведение
You will learn
- Что означает рендеринг в React.
- Когда и почему React рендерит компонент.
- Шаги, связанные с рендерингом компонента на экране.
- Почему рендеринг не всегда приводит к обновлению DOM.
Представьте, что ваши компоненты — это повара на кухне, собирающие вкусные блюда из ингредиентов. В этом сценарии React — это официант, который выполняет запросы клиентов и приносит им их заказы. Этот процесс запроса и подачи пользовательского интерфейса состоит из трех этапов:
- Триггер рендеринга (доставка заказа гостя на кухню)
- Рендеринг компонента (подготовка заказа на кухне)
- Фиксация в DOM (размещение заказа на столе)
Illustrated by Rachel Lee Nabors
Step 1: Триггер рендера
Есть две причины для рендера компонента:
- Это первоначальный рендеринг компонента.
- Компонент (или один из его дочерних’) стейт был обновлён.
Начальный рендер
Когда ваше приложение запускается, вам необходимо вызвать начальный рендеринг. Фреймворки и песочницы иногда скрывают этот код, но он выполняется вызовом функции createRoot
с целевым узлом DOM, а затем вызывая его метод render
вашим компонентом:
import Image from './Image.js'; import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')) root.render(<Image />);
Попробуйте закомментировать вызов root.render()
и увидите, как компонент исчезнет!
Ре-рендер, когда стейт обновляется
После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции set
Обновление стейта компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетителя ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода).
Illustrated by Rachel Lee Nabors
Step 2: React рендерит ваш компонент
После запуска рендера React вызывает ваши компоненты, чтобы определить, что отобразить на экране. *“Рендеринг” — это обращение React к вашим компонентам.
- На начальном рендере, React вызовет корневой компонент.
- Для последующих рендерингов React будет вызывать функцию компонента, обновление стейта которого вызвало рендеринг.
Этот процесс рекурсивен: если обновленный компонент возвращает какой-то другой компонент, React будет рендерить этот компонент следующим, и если этот компонент тоже что-то возвращает, он будет рендерить этот компонент следующим, и так далее. Этот процесс будет продолжаться до тех пор, пока не останется вложенных компонентов и React не будет точно знать, что должно быть отображено на экране.
В следующем примере React вызовет Gallery()
и Image()
несколько раз:
export default function Gallery() { return ( <section> <h1>Inspiring Sculptures</h1> <Image /> <Image /> <Image /> </section> ); } function Image() { return ( <img src="https://i.imgur.com/ZF6s192.jpg" alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals" /> ); }
- На начальном рендере, React создаст DOM ноды для
<section>
,<h1>
, и трёзх<img>
тегов. - Во время повторного ре-рендеринга, React вычислит, какие из их свойств, если таковые имеются, изменились с момента предыдущего рендеринга. Он ничего не будет делать с этой информацией до следующего шага, фазы фиксации.
Deep Dive
Поведение по умолчанию — рендеринг всех компонентов, вложенных в обновленный компонент, — не является оптимальным с точки зрения производительности, если обновляемый компонент находится очень высоко в дереве. Если вы столкнулись с проблемой производительности, есть несколько способов ее решения, описанных в разделе Производительность. Не оптимизируйте преждевременно!
Step 3: React фиксирует изменения в DOM
После рендеринга (вызова) ваших компонентов React модифицирует DOM.
- На начальном рендере, React использует
appendChild()
DOM API, чтобы вставить все DOM ноды, которые он создал на экране. - Для ре-рендеров, React будет применять минимально необходимые операции (вычисляемые во время рендеринга!), чтобы DOM соответствовал последнему выводу рендеринга.
** React изменяет узлы DOM, только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в <input>
, обновляя его значение
, но текст не исчезает при повторном рендеринге компонента:
export default function Clock({ time }) { return ( <> <h1>{time}</h1> <input /> </> ); }
Это работает, потому что в предыдущий раз, React обновил значение <h1>
с новым time
. Он видит, что <input>
появляется в том же месте JSX, поэтому React не трогает <input>
— или его value
!
Epilogue: Browser paint
После того как рендеринг завершен и React обновил DOM, браузер перерисовывает экран. Хотя этот процесс известен как “браузерный рендеринг”, мы будем называть его “рисованием”, чтобы избежать путаницы в документации.
Illustrated by Rachel Lee Nabors