Перейти к содержимому
На этой странице

Хуки в React

Все темы React Developer

Что такое “хуки” (hooks) в React и для чего они используются?

Хуки ( Hooks ) — это функции, которые позволяют использовать состояние и другие возможности React в функциональных компонентах.

Основные хуки:

  1. useState:

    • Управляет состоянием в функциональных компонентах.

    • Пример:

      const [count, setCount] = useState(0);
  2. useEffect:

    • Выполняет побочные эффекты, такие как загрузка данных, в функциональных компонентах.

    • Пример:

      useEffect(() => {
        // Выполнение побочного эффекта
      }, []);
  3. useContext:

    • Использует контекст для доступа к глобальным данным.

    • Пример:

      const value = useContext(MyContext);
  4. useReducer:

    • Управляет сложным состоянием с помощью редюсеров.

    • Пример:

      const [state, dispatch] = useReducer(reducer, initialState);
  5. useMemo:

    • Мемоизирует вычисленные значения для оптимизации производительности.

    • Пример:

      const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  6. useCallback:

    • Мемоизирует функции для оптимизации производительности.

    • Пример:

      const memoizedCallback = useCallback(() => {
        doSomething(a, b);
      }, [a, b]);

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


Как создать собственный хук в React?

Собственный хук (custom hook) позволяет абстрагировать и повторно использовать логику состояния и эффектов в функциональных компонентах.

Шаги:

  1. Создайте функцию, название которой начинается с use:

    • Собственные хуки должны следовать соглашению об именовании, начинаясь с use.
  2. Используйте внутри функции стандартные хуки React (useState, useEffect, и т.д.):

    • Собственный хук может использовать любые стандартные хуки React.
  3. Возвращайте необходимые значения или функции из собственного хука:

    • Возвращайте данные и функции, которые должны быть доступны в компоненте.

Пример:

import { useState, useEffect } from "react";

// Создание собственного хука для получения данных
const useFetchData = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const result = await response.json();
        setData(result);
        setLoading(false);
      } catch (err) {
        setError(err);
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default useFetchData;

Использование собственного хука в компоненте:

import React from "react";
import useFetchData from "./useFetchData";

const MyComponent = () => {
  const { data, loading, error } = useFetchData("https://api.example.com/data");

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{JSON.stringify(data)}</div>;
};

export default MyComponent;

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


Какие особенности имеют хуки useEffect и useLayoutEffect?

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

useEffect:

  1. Выполнение после рендеринга:

    • Выполняется после commit. Обычно браузер успевает нарисовать экран до эффекта, но эффект, вызванный взаимодействием пользователя, может выполниться до отрисовки.

    • Подходит для операций, не влияющих на отображение, таких как данные, запросы и подписки.

  2. Использование:

    useEffect(() => {
      // Побочные эффекты, например, загрузка данных
      return () => {
        // Очистка при размонтировании
      };
    }, [dependencies]); // Зависимости

useLayoutEffect:

  1. Выполнение перед отрисовкой браузером:

    • Выполняется после обновления DOM, но до отрисовки экрана браузером. Эффект и обновления состояния внутри него блокируют эту отрисовку.

    • Подходит для операций, влияющих на макет и измерения, таких как анимации и манипуляции с DOM.

  2. Использование:

    useLayoutEffect(() => {
      // Побочные эффекты, например, измерения DOM
      return () => {
        // Очистка при размонтировании
      };
    }, [dependencies]); // Зависимости
  • useEffect: Выполняется после рендеринга, подходит для асинхронных операций и побочных эффектов, не влияющих на макет.

  • useLayoutEffect: выполняется после commit, до отрисовки браузером; подходит для измерения DOM перед показом результата.


Зачем useEffect возвращает cleanup-функцию?

Cleanup отменяет или симметрично завершает то, что setup эффекта начал. React вызывает его перед повторным запуском эффекта с изменившимися зависимостями и при размонтировании. Поэтому подписку снимают тем же handler, таймер очищают, запрос отменяют, а внешний widget уничтожают. В development Strict Mode React дополнительно выполняет цикл setup-cleanup-setup, чтобы обнаружить несимметричный код; на production-поведение этого как гарантии не полагаются. Cleanup не должен без причины обновлять React state. Хороший тест: после cleanup внешний мир выглядит так, будто этот запуск эффекта не происходил.


Какие ресурсы нужно освобождать при размонтировании React-компонента?

Освобождают таймеры и animation frame, снимают DOM и библиотечные подписки, закрывают WebSocket или EventSource, отменяют поддерживаемые запросы. IntersectionObserver, ResizeObserver и MutationObserver отключают; созданный chart, map, editor или media instance уничтожают его API. Для shared connection cleanup уменьшает reference count, а не обязательно закрывает ресурс для всех. Очистка должна быть симметрична конкретному setup и безопасна при повторном вызове. Если библиотека сама управляет только DOM-узлом, удаляемым React, отдельный cleanup может не понадобиться, но это подтверждают её контрактом.


Как выбирать зависимости useEffect и избегать stale closure?

В зависимости включают каждое reactive value, прочитанное внутри эффекта: props, state и функции или объекты из тела компонента. Это не ручной выбор частоты запуска, а описание данных эффекта. Пропуск создаёт stale closure, где callback видит старые значения. Если объект меняется на каждом render, его создают внутри эффекта, мемоизируют по настоящим зависимостям либо выносят стабильную часть наружу. Для update из предыдущего state используют функциональный setter. Правило exhaustive-deps лучше исправлять изменением структуры; отключение допустимо только при доказанном инварианте, который код делает очевидным.


Когда useEffect запускается без массива зависимостей?

Если второй аргумент не передан, effect запускается после каждого commit компонента. Перед новым запуском React сначала выполняет cleanup предыдущего. Если effect безусловно меняет state, а это изменение вызывает новый render, легко получить цикл; React прекратит его ошибкой только после множества обновлений. Это не значит, что всегда нужно добавить пустой массив. Нужно описать реальные reactive dependencies или убрать effect, если значение можно вычислить во время render. В development Strict Mode возможен дополнительный setup-cleanup цикл, поэтому эффект обязан быть симметричным.


Какие значения стоит хранить в useRef помимо DOM-узла?

useRef хранит изменяемое значение между рендерами без запуска нового render. В нём удобно держать ID таймера, предыдущие данные для сравнения, AbortController, экземпляр стороннего API или последнее значение, которое читает внешний callback. Ref подходит только тому, что не участвует в текущем JSX. Если изменение должно сразу отобразиться, нужен state. Не стоит читать или писать ref.current во время render, кроме предсказуемой ленивой инициализации: это нарушает чистоту компонента. Cleanup освобождает внешний ресурс, на который указывает ref.

Собеседования: React

Смотри записи интервью, узнай, какие вопросы задают и как отвечают кандидаты.

Вопросы и ответы

Не нашли ответ? Напишите мне в чат. Я делаю Шпаргалку и сам отвечаю на сообщения. Расскажите, что не работает или чего вам не хватает. Может, смогу сразу взять это в работу.

Откуда взяты вопросы?

Из реальных собеседований. Основой подборки стал опыт Вадима Новосёлова: он проходил интервью и записывал вопросы. Подробнее о материалах.

Насколько эти вопросы актуальны?

Эти вопросы встречались нам на реальных собеседованиях в 2025 году. Мы регулярно проходим собеседования и пополняем подборку новыми вопросами. Основы профессии и ключевые технологии остаются востребованными годами, а детали конкретных инструментов и версий стоит сверять с текущей документацией.

На какой уровень рассчитана подборка?

Мы проходили собеседования на вакансии уровня Middle+, а иногда и на Senior-позиции. Вопросы из этих интервью вошли в подборку. Направления работы: React-разработчик, Frontend-разработчик. Глубина обсуждения зависит от вакансии: будь готов объяснить основную идею, привести практический пример и разобрать ограничения и альтернативы решения.

Этот вопрос точно будет на моём собеседовании?

Гарантии нет: набор вопросов зависит от компании, задач команды, уровня вакансии и самого интервьюера. Эти вопросы уже встречались на реальных собеседованиях, но на твоём интервью ту же тему могут проверить другой формулировкой, практической задачей или обсуждением твоего опыта. Используй подборку, чтобы разобраться в теме: объясняй идею своими словами, приводи примеры и готовься обсудить ограничения и альтернативы решения. Так будет проще ответить и на знакомый вопрос, и на неожиданные уточнения.