Это часть 1 & часть 2 полного руководства по React re-renders. В руководстве объясняется, что такое рендеринг, что такое необходимый и ненужный рендеринг, что может вызвать повторный рендеринг компонента React.
Полное руководство также включает наиболее важные паттерны, которые могут помочь предотвратить повторные рендеры, и несколько анти-паттернов, которые приводят к ненужным повторным рендерам и низкой производительности в результате. Каждый паттерн и антипаттерн сопровождается наглядным пособием и примером рабочего кода.
Полное содержание руководства:
- Часть 1: что такое re-render в React?
- Часть 2: когда React-компонент сам себя рендерит?
- Часть 3: предотвращение повторного рендеринга с помощью композиции
- Часть 4: предотвращение повторного рендеринга с помощью React.memo
- Часть 5: улучшение производительности повторных рендеров с помощью useMemo/useCallback
- Часть 6: улучшение производительности рендеринга списков
- Часть 7: предотвращение повторного рендеринга, вызванного Context
- Что такое повторный рендеринг в React?
- 🧐 Что такое необходимый и ненужный рендеринг?
- Когда React-компонент сам себя рендерит?
- 🧐 Причина повторных рендеров: изменение состояния
- 🧐 Причина рендеринга: рендеринг родителя
- 🧐 Причина повторного рендеринга: изменение контекста
- 🧐 Причина повторных рендеров: изменения в хуках
- ⛔️ Причина повторных рендеров: изменения реквизитов (большой миф)
Что такое повторный рендеринг в React?
Говоря о производительности React, мы должны обратить внимание на два основных этапа:
- первоначальный рендеринг — происходит, когда компонент впервые появляется на экране
- повторный рендеринг — второй и любой последующий рендеринг компонента, который уже находится на экране.
Повторный рендеринг происходит, когда React необходимо обновить приложение какими-то новыми данными. Обычно это происходит в результате взаимодействия пользователя с приложением или поступления внешних данных через асинхронный запрос или какую-либо модель подписки.
Неинтерактивные приложения, которые не имеют асинхронных обновлений данных, никогда не будут перерисовываться, и поэтому им не нужно заботиться об оптимизации производительности перерисовки.
🧐 Что такое необходимый и ненужный рендеринг?
Необходимый рендеринг — рендеринг компонента, который является источником изменений, или компонента, который непосредственно использует новую информацию. Например, если пользователь набирает текст в поле ввода, компонент, управляющий его состоянием, должен обновляться при каждом нажатии клавиши, т.е. перерисовываться.
Ненужный повторный рендеринг — повторный рендеринг компонента, который распространяется по приложению через различные механизмы повторного рендеринга из-за ошибки или неэффективной архитектуры приложения. Например, если пользователь набирает текст в поле ввода, а вся страница перерисовывается при каждом нажатии клавиши, то страница перерисовывается без необходимости.
Сами по себе ненужные повторные рендеринги не являются проблемой: React работает очень быстро и обычно справляется с ними так, что пользователи ничего не замечают.
Однако если рендеринг происходит слишком часто и/или на очень тяжелых компонентах, это может привести к «лагам» в работе пользователя, заметным задержкам при каждом взаимодействии или даже к тому, что приложение перестанет реагировать.
Когда React-компонент сам себя рендерит?
Есть четыре причины, по которым компонент может перерендерить себя: изменения состояния, перерендеринг родителя (или детей), изменения контекста и изменения хуков. Существует также большой миф о том, что рендеринг происходит при изменении реквизитов компонента. Само по себе это не так (см. объяснение ниже).
🧐 Причина повторных рендеров: изменение состояния
Когда состояние компонента меняется, он перерисовывается. Обычно это происходит либо в обратном вызове, либо в хуке useEffect
.
Изменения состояния являются «корневым» источником всех повторных рендерингов.
Смотрите пример в codesandbox
🧐 Причина рендеринга: рендеринг родителя
Компонент будет рендериться сам, если рендерится его родитель. Или, если посмотреть на это с другой стороны: когда компонент рендерится, он также рендерит все свои дочерние компоненты.
Это всегда идет «вниз» по дереву: рендеринг дочернего компонента не вызывает рендеринга родительского. (Здесь есть несколько оговорок и крайних случаев, подробнее см. в полном руководстве: Тайна React Element, дети, родители и повторные рендеры).
Смотрите пример в codesandbox
🧐 Причина повторного рендеринга: изменение контекста
Когда значение в Context Provider меняется, все компоненты, которые используют этот Context, будут перерисованы, даже если они не используют измененную часть данных напрямую. Эти рендеры нельзя предотвратить с помощью мемоизации напрямую, но есть несколько обходных путей, которые могут это имитировать (см. часть 7: предотвращение рендеров, вызванных Context).
Смотрите пример в codesandbox
🧐 Причина повторных рендеров: изменения в хуках
Все, что происходит внутри хука, «принадлежит» компоненту, который его использует. Здесь действуют те же правила относительно изменений Контекста и Состояния:
- изменение состояния внутри хука вызовет непредотвратимый повторный рендеринг компонента-«хозяина»
- если хук использует Context и значение Context изменится, это вызовет непредотвратимый повторный рендеринг «главного» компонента.
Крючки могут быть соединены в цепочку. Каждый хук внутри цепочки по-прежнему «принадлежит» компоненту «хозяина», и к любому из них применимы одни и те же правила.
См. пример в codesandbox
⛔️ Причина повторных рендеров: изменения реквизитов (большой миф)
Не имеет значения, изменяются ли реквизиты компонента или нет, когда речь идет о повторных рендерингах не мемоизированных компонентов.
Для того чтобы реквизиты изменились, они должны быть обновлены родительским компонентом. Это означает, что родительский компонент должен будет перерендериться, что вызовет перерендеринг дочернего компонента независимо от его реквизитов.
См. пример в codesandbox
Только когда используются техники мемоизации (React.memo
, useMemo
), тогда изменение реквизитов становится важным.
Ознакомьтесь с остальной частью руководства здесь:
- Часть 1: что такое re-render в React?
- Часть 2: когда компонент React сам себя рендерит?
- Часть 3: предотвращение повторного рендеринга с помощью композиции
- Часть 4: предотвращение повторного рендеринга с помощью React.memo
- Часть 5: улучшение производительности повторных рендеров с помощью useMemo/useCallback
- Часть 6: улучшение производительности рендеринга списков
- Часть 7: предотвращение повторных рендеров, вызванных Context
Первоначально опубликовано на https://www.developerway.com. На сайте есть еще больше подобных статей 😉
Подпишитесь на рассылку, подключитесь на LinkedIn или следуйте в Twitter, чтобы получить уведомление о выходе следующей статьи.