Храните значения барабанов массивом, блокируйте повторный запуск и определяйте результат после завершения всех вращений.
Реализуйте компонент 'Слот-машина' с тремя барабанами: нужно хранить текущие значения барабанов, реализовать запуск вращения (RunSpinner), состояние disabled для кнопки, определить победу/поражение и корректно отображать сообщение, а также сделать компонент масштабируемым на произвольное количество барабанов.
Храните значения барабанов массивом, блокируйте повторный запуск и определяйте результат после завершения всех вращений.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Храните значения барабанов массивом, блокируйте повторный запуск и определяйте результат после завершения всех вращений.
Ниже предполагается адаптер runSpinner(index), возвращающий Promise конечного числа и управляющий анимацией. count — положительное целое; при его изменении компонент нужно перемонтировать через key. Ошибки ждём у всех барабанов, чтобы не разблокировать кнопку раньше времени.
import { useEffect, useRef, useState } from 'react';
function SlotMachine({ count = 3, runSpinner }) {
const [values, setValues] = useState(() => Array(count).fill(null));
const [running, setRunning] = useState(false);
const [message, setMessage] = useState('');
const busy = useRef(false);
const mounted = useRef(false);
useEffect(() => {
mounted.current = true;
return () => { mounted.current = false; };
}, []);
async function run() {
if (busy.current) return;
busy.current = true;
setRunning(true);
setMessage('');
const results = await Promise.allSettled(
Array.from({ length: count }, (_, i) =>
Promise.resolve().then(() => runSpinner(i)))
);
busy.current = false;
if (!mounted.current) return;
const next = results.map(r => r.status === 'fulfilled' ? r.value : null);
setValues(next);
setRunning(false);
setMessage(results.some(r => r.status === 'rejected')
? 'Ошибка вращения'
: next.every(v => v === next[0]) ? 'Победа!' : 'Попробуйте ещё');
}
return <div>
<div>{values.map((v, i) => <span key={i}>{v ?? '—'} </span>)}</div>
<button disabled={running} onClick={run}>Запустить</button>
<p role="status">{message}</p>
</div>;
}
Ссылка busy защищает от повторного старта ещё до следующего рендера. Реальный API RunSpinner следует подключить через указанный адаптер.