No history yet

Понятие побочных эффектов

Компоненты как чистые функции

Представьте, что компонент React — это надежный повар, который готовит блюдо по строгому рецепту. Вы даете ему ингредиенты (данные, или «пропсы»), а он всегда возвращает вам одно и то же блюдо (часть пользовательского интерфейса). Если вы дадите ему те же самые ингредиенты завтра, он приготовит точно такое же блюдо.

В программировании такой предсказуемый процесс описывается понятием чистая функция (pure function). Главная задача чистой функции — вычислить и вернуть результат, не влияя ни на что за ее пределами. Компоненты React спроектированы так, чтобы в идеале вести себя именно как чистые функции. Их основная работа — это рендеринг: они принимают данные и на их основе описывают, как должен выглядеть интерфейс. Этот процесс должен быть предсказуемым.

Что такое побочные эффекты

Иногда компоненту нужно сделать что-то, что выходит за рамки простого отображения интерфейса. Например:

  • Отправить данные на сервер: когда пользователь заполняет форму, ее нужно куда-то отправить.
  • Изменить заголовок вкладки в браузере: чтобы он соответствовал открытой странице.
  • Запустить таймер: например, для обратного отсчета.
  • Подписаться на внешние события: например, отслеживать, в сети ли пользователь.

Все эти действия, которые происходят «за кулисами» и взаимодействуют с внешним миром (браузером, сервером, таймерами), называются побочными эффектами (side effects). Они необходимы для создания живых, интерактивных приложений, но они нарушают «чистоту» компонента, потому что их результат не связан напрямую с отрисовкой UI.

Побочный эффект — это любое взаимодействие с миром за пределами вашего компонента.

Почему эффекты нельзя вызывать напрямую

Может показаться логичным просто вставить код для побочного эффекта прямо в тело компонента. Например, чтобы изменить заголовок страницы:

function Greeting() {
  // ❌ Неправильно! Эффект вызывается во время рендеринга.
  document.title = "Добро пожаловать!";

  return <h1>Привет, мир!</h1>;
}

Проблема в том, что React может вызывать функцию вашего компонента (то есть, проводить рендеринг) множество раз и по разным причинам, а не только при первом отображении. Например, когда состояние родительского компонента меняется, React перерисовывает и дочерние компоненты.

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

Решение: хук `useEffect`

Для безопасного управления побочными эффектами в React есть специальный инструмент — хук useEffect. Он позволяет «отложить» выполнение побочного эффекта до тех пор, пока React не закончит все расчеты и не обновит (то есть, не отрисует интерфейс на экране).

Думайте о useEffect как о специальном месте, куда вы выносите весь код, который не связан напрямую с отрисовкой. Это позволяет React сначала быстро показать пользователю обновленный интерфейс, а уже потом, в фоновом режиме, выполнить все необходимые побочные эффекты.

Вот как правильно изменить заголовок страницы:

import { useEffect } from 'react';

function Greeting() {
  useEffect(() => {
    // ✅ Правильно! Эффект выполняется после рендеринга.
    document.title = "Добро пожаловать!";
  });

  return <h1>Привет, мир!</h1>;
}

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

Quiz Questions 1/5

Что из нижеперечисленного лучше всего описывает концепцию «чистой функции» в контексте компонентов React?

Quiz Questions 2/5

Почему размещение побочного эффекта (например, сетевого запроса) непосредственно в теле функции компонента является плохой практикой?