useEffect должен возвращать очистку, а не Promise. Запустите асинхронную работу внутри эффекта, сохраните одну ссылку на scroll-обработчик и игнорируйте поздний ответ.
Починить компонент React, получающий случайное число и отслеживающий прокрутку
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 объявлена вне компонента.