🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Почему дочерние эффекты выполняются раньше родительских? Как архитектура React Fiber влияет на порядок вызова хуков? Ответы на эти вопросы помогут лучше понять механизмы работы React и писать более предсказуемый код.
🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Привет, друзья! Я – Кирилл Мыльников, frontend-разработчик в ГК Юзтех. Сегодня мы поговорим о useEffect — одном из самых часто используемых хуков в React. Этот хук является мощным инструментом для управления побочными эффектами в функциональных компонентах. Мы рассмотрим, как он работает, на что следует обращать внимание и как избежать распространенных ошибок. Статья будет полезна как новичкам, так и опытным разработчикам.

Давайте начнем вот с такого примера и подумайте в каком порядке будут вызываться console.log?

Пример 1

<b>Codesandbox: </b><a href="https://codesandbox.io/p/sandbox/3hdx5r?file=%2Fsrc%2FApp.js%3A12%2C1" target="_blank" rel="noopener noreferrer nofollow">https://codesandbox.io/p/sandbox/3hdx5r?file=%2Fsrc%2FApp.js%3A12%2C1</a>
Codesandbox: https://codesandbox.io/p/sandbox/3hdx5r?file=%2Fsrc%2FApp.js%3A12%2C1

Если вы ответили неправильно ничего страшного, как раз в этой статье разберем, что тут происходит. На самом деле это явно не документировано или объяснено на официальном сайте React.

Для начала вспомним что такое useEffect и как он работает:

useEffect — это асинхронный хук в React, который позволяет выполнять побочные эффекты в функциональных компонентах. Побочные эффекты могут включать в себя такие операции, как запросы данных, подписки, ручные изменения DOM и таймеры. useEffect заменяет методы жизненного цикла, такие как componentDidMount, componentDidUpdate и componentWillUnmount, которые используются в классовых компонентах

Особенности:

  1. Выполняется после рендеринга. useEffect выполняется после того, как компонент был отрендерен в DOM.Это гарантирует, что все элементы DOM доступны для манипуляции.
  2. Вы можете передавать вторым аргументом массив зависимостей, то данный хук будет выполнятся только тогда, когда изменятся данные значения.
  3. Mожет возвращать функцию очистки, которая будет вызвана перед тем, как компонент будет размонтирован или перед следующим выполнением useEffect. Это полезно для отмены подписок или таймеров.

Пример работы useEffect:

🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Также бонусом можно разобрать, как работает useLayoutEffect, принцип работы как у useEffect, только он синхронный и работает точно также как и в классовых компонентах

Пример работы useLayoutEffect:

🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Давайте вспомним, как работает жизненный цикл, который делится на 3 этапа: Trigger – Render – Commit

Trigger

Существует две причины для рендеринга компонента:

  • Это начальный рендеринг компонента.
  • Состояние компонента (или одного из его предков) обновлено.

Rendering

  • React вызывает компонент и работает над обновленным состоянием
  • Создает новый DOM узел.

Commit

  • Манипуляция с DOM
  • Запуск эффектов
👨‍💻🎨 Библиотека фронтендера
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека фронтендера»

React Fiber

React Fiber – это архитектура, используемая в React для управления иерархией компонентов и оптимизации процесса рендеринга. Она основа на деревовидной структуре, где каждый узел представляет собой компонент и его состояние.

Каждый узел в этом дереве называется «узлом волокна» (fiber node). Узлы волокна содержат информацию о props и state компонентов. При каждом обновлении состоянии React создается новое дерево волокон и сравнивает его со старым деревом, чтобы определить, какие изменения необходимо внести в DOM. Этот процесс позволяет React эффективно управлять обновлениями и обеспечивать плавный пользовательский интерфейс.

Отсюда следует, что React Fiber значительно улучшает производительность и отзывчивость приложений, особенно в случаях, когда требуется обработка большого количества обновлений

Пример React Fiber

🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Как правило, в React используется один и тот же алгоритм обхода во многих случаях

Render Phase

React Fiber работает, обходя дерево компонентов и выполняя два ключевых этапа на каждом узле.

На первом этапе React вызывает компонент и проводит процесс согласования (reconciliation). В этот момент React сравнивает текущее состояние и свойства компонента с новыми данными и помечает узлы волокон, которые требуют обновления.

На втором этапе React создает или обновляет соответствующие DOM-узлы на основе изменений, выявленных на первом этапе.

После завершения этих шагов React генерирует новое дерево волокон с обновленными DOM-узлами. Однако фактические изменения в DOM (мутации) происходят только на этапе коммита (commit phase), что обеспечивает плавное и эффективное обновление пользовательского интерфейса.

Commit Phase

Фаза фиксации, или коммита, — это этап, на котором происходят фактические изменения в DOM и выполняется очистка эффектов (useEffect). Хотя общий шаблон обхода дерева остается прежним, мутации DOM и очистка эффектов обрабатываются в отдельных проходах.

В этом разделе мы сосредоточимся исключительно на процессе очистки эффектов, оставив в стороне мутации DOM.

Сommitings Effects

React использует тот же алгоритм обхода дерева, но с одним важным отличием: вместо проверки наличия дочерних элементов у узла, он проверяет наличие поддерева. Это логично, так как только компоненты React могут содержать хуки useEffect. Например, узел DOM, такой как <p>, не будет содержать никаких хуков React.

На первом этапе обхода не происходит никаких действий. Однако на втором этапе выполняются определенные эффекты, связанные с хуками.

Этот подход объясняет, почему дочерние эффекты запускаются до родительских эффектов

Теперь, возвращаясь к первому примеру, должно стать понятным, почему так происходит

Пример:

🤷🏻‍♂️ Как избежать ошибок при использовании useEffect в React?

Понимание того, как и когда React выполняет хуки useEffect, может значительно помочь в предотвращении мелких ошибок и неожиданного поведения, особенно при работе с комплексными структурами компонентов.

Материалы

react - https://react.dev/

useEffecthttps://react.dev/reference/react/useEffect

useLayoutEffecthttps://react.dev/reference/react/useLayoutEffect

МЕРОПРИЯТИЯ

Комментарии

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ