Починить компонент React, получающий случайное число и отслеживающий прокрутку

useEffect должен возвращать очистку, а не Promise. Запустите асинхронную работу внутри эффекта, сохраните одну ссылку на scroll-обработчик и игнорируйте поздний ответ.

Короткий ответ

Что ответить на собеседовании

useEffect должен возвращать очистку, а не Promise. Запустите асинхронную работу внутри эффекта, сохраните одну ссылку на scroll-обработчик и игнорируйте поздний ответ.

Подробный разбор

Ответ с пояснениями

Условие

В задаче требуется исправить несколько типичных ошибок в React‑компоненте, который асинхронно получает случайное число и отображает текущую позицию прокрутки окна. Компонент написан с использованием хуков useState и useEffect, однако в нём присутствуют проблемы, такие как использование async‑функции непосредственно в useEffect, отсутствие массива зависимостей и некорректное управление обработчиком события scroll.

import React, { useState, useEffect } from "react";

// Имитируем запрос к серверу, возвращаем случайное число асинхронно
const getRandomNumber = () => Promise.resolve(Math.random());

const RandomNumberWithScroll = () => {
    const [randomNum, setRandomNum] = useState();
    const [scrollPos, setScrollPos] = useState();

    useEffect(async () => {
        setRandomNum(await getRandomNumber());
        window.addEventListener("scroll", () => setScrollPos(window.scrollY));
        return () =>
            window.removeEventListener("scroll", () => setScrollPos(window.scrollY));
    });

    return (
        <div>
            <div>Number: {randomNum}</div>
            <div>Scroll: {scrollPos}</div>
        </div>
    );
};

export default RandomNumberWithScroll;

Необходимо переписать useEffect так, чтобы он корректно обрабатывал асинхронный запрос и правильно добавлял/удалял обработчик прокрутки, а также добавить массив зависимостей, если это требуется.

Ответ

useEffect должен возвращать очистку, а не Promise. Запустите асинхронную работу внутри эффекта, сохраните одну ссылку на scroll-обработчик и игнорируйте поздний ответ.

Замените эффект следующим кодом; добавьте const [error, setError] = useState('') и отображение ошибки.

useEffect(() => {
  let active = true;
  const onScroll = () => setScrollPos(window.scrollY);
  onScroll();
  window.addEventListener('scroll', onScroll, { passive: true });
  getRandomNumber().then(
    value => { if (active) setRandomNum(value); },
    () => { if (active) setError('Не удалось получить число'); }
  );
  return () => {
    active = false;
    window.removeEventListener('scroll', onScroll);
  };
}, []);

Две внешне одинаковые стрелки являются разными объектами функций, поэтому исходная очистка не удаляла слушатель. Пустой массив зависимостей подходит, поскольку getRandomNumber объявлена вне компонента.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее