Для увеличения используйте setCurrent(value => value + 1), чтобы не зависеть от захваченного current. Для лога последнего committed значения храните его отдельно в ref.
Устранить баги в React‑компоненте без указания зависимостей в useEffect
Для увеличения используйте setCurrent(value => value + 1), чтобы не зависеть от захваченного current. Для лога последнего committed значения храните его отдельно в ref.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо исправить логику таймера в функциональном React‑компоненте так, чтобы он корректно обновлял состояние без добавления зависимостей в массив зависимостей useEffect.
import React, { useState, useEffect } from 'react';
const Counter = () => {
const [current, setCurrent] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
console.log(current);
setCurrent(current + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
return <div>Count: {current}</div>;
};
export default Counter;
В данном примере нужно обеспечить правильное захватывание актуального значения счётчика внутри setInterval, не полагаясь на массив зависимостей useEffect.
Ответ
Для увеличения используйте setCurrent(value => value + 1), чтобы не зависеть от захваченного current. Для лога последнего committed значения храните его отдельно в ref.
const latest = React.useRef(current);
React.useLayoutEffect(() => { latest.current = current; });
useEffect(() => {
const intervalId = setInterval(() => {
console.log(latest.current);
setCurrent(value => value + 1);
}, 1000);
return () => clearInterval(intervalId);
}, []);
Массив зависимостей основного useEffect остаётся пустым, таймер создаётся один раз за монтирование. Layout-эффект без массива синхронизирует ref после каждого commit. Не помещайте console.log внутрь updater: React может повторно вызвать его при проверке чистоты. Сам инкремент не требует ref, он нужен только для чтения в лог.