React. Почему по истечению таймера кнопки не переключаются обратно?
Когда я нажимаю на кнопку - она становиться disabled. По истечению таймера, кнопка должна быть снова активна, но этого не происходит. Почему кнопки не переключаются обратно по истечении таймера? Подозреваю, что проблема в функции handleDisabled. Я поставил туда debugger и увидел, что item в функции handleDisabled undefined. Что я делаю не так и как это исправить?
Вот мой код со всеми необходимыми данными:
const CurrentEventsItem = () => {
const [timeLeft, setTimeLeft] = useState( 15);
const getPadTime = (time) => time.toString().padStart(2, "0");
const minutes = getPadTime(Math.floor(timeLeft / 60));
const seconds = getPadTime(timeLeft - minutes * 60);
useEffect(() => {
const interval = setInterval(() => {
setTimeLeft((timeLeft) =>
timeLeft >= 1 ? timeLeft - 1 : handleDisabled() || 15
);
}, 1000);
return () => clearInterval(interval);
}, []);
const getRandomElements = (array, count) => {
const shuffled = array.sort(() => 0.5 - Math.random());
return shuffled.slice(0, count);
};
const [appState, changeState] = useState( [])
useEffect(() => {
getCurrentEvents()
}, [])
const getCurrentEvents = async() => {
const data = await ProductDataService.getAllCurrentEvents()
changeState(data.docs.map((doc) => ({...doc.data(), id: doc.id})))
}
const [selectedItems, setSelectedItems] = useState(() =>
getRandomElements(appState, 3)
);
useEffect(() => {
if (timeLeft === 0) {
const elements = getRandomElements(appState, 3);
setSelectedItems(elements);
}
}, [timeLeft, appState]);
const toggleActiveStyles = (index) => {
if (appState[index].statusItem) {
return "current__events__hot-price disabled";
} else {
return "current__events__hot-price";
}
};
const toggleActiveStylesBtns = (index) => {
if (appState[index].statusItem) {
return "current__events__btn-green disabled";
} else {
return "current__events__btn-green";
}
};
const toggleActive = (item) => {
item.statusItem = !item.statusItem;
changeState([...appState]);
setSelectedItems([...selectedItems]);
};
const handleDisabled = () => {
appState.forEach((item) => {
if (item.statusItem) {
toggleActive(item);
}
});
};
return (
<>
<div className='current__events__wrapper'>
{selectedItems.map((item, index) =>
<div className="current__events__hot-price__item" key={index}>
<div className={toggleActiveStyles(index)}>
<h5 className="current__events__card-title__large">Hot Price</h5>
</div>
<div className="current__events__image">
<img src={item.avatar} alt='user' className="rounded-circle" width='75' height='75'/>
</div>
<div className="current__events__info">
<h4 className="current__events__title__middle">{item.title}</h4>
</div>
<div className="current__events__timer">
<span>{minutes}</span>
<span>:</span>
<span>{seconds}</span>
</div>
<button className={toggleActiveStylesBtns(index)} onClick={() => toggleActive(item)} disabled={item.statusItem}>СДЕЛАТЬ ХОД</button>
</div>
)}
</div>
</>
)
}
Ответы (1 шт):
Если честно, долго пытался именно менять код, но устал и просто практически переписал с нуля пошагово, следуя поставленным вами условиям. Пытался писать близко к вашему стилю. Одна вещь очень сильно путала - это то, что на true вы кнопки отключаете.
Вот что получилось:
App.js
import { useState, useEffect } from 'react';
import './styles.css';
import CurrentEventsItem from './CurrentEventsItem';
import ProductDataService from './productServices';
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => async () => await getCurrentEvents(), []);
const getCurrentEvents = async () => {
const data = await ProductDataService.getAllCurrentEvents();
setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
return <CurrentEventsItem items={items} />;
}
CurrentEventsItem.js
import { useState, useEffect } from "react";
const getRandomElements = (array, count) => {
const shuffled = array.sort(() => 0.5 - Math.random());
return shuffled.slice(0, count);
};
const getPadTime = (time) => time.toString().padStart(2, "0");
const CurrentEventsItem = ({items}) => {
const [timeLeft, setTimeLeft] = useState(5);
const [appState, changeState] = useState(items);
const [selectedItems, setSelectedItems] = useState(getRandomElements(appState, 3));
const minutes = getPadTime(Math.floor(timeLeft / 60));
const seconds = getPadTime(timeLeft - minutes * 60);
useEffect(() => {
changeState(items);
setSelectedItems(getRandomElements(items, 3));
}, [items])
useEffect(() => {
const interval = setInterval(() => {
setTimeLeft((timeLeft) => {
if (timeLeft > 0) return timeLeft - 1;
enableAll();
setSelectedItems(getRandomElements(appState, 3));
return 5;
});
}, 1000);
return () => clearInterval(interval);
}, [appState]);
const toggleActiveStyles = (index) => `current__events__hot-price${
appState[index].statusItem ? ' disabled' : ''
}`;
const toggleActiveStylesBtns = (index) => `current__events__btn-green${
appState[index].statusItem ? ' disabled' : ''
}`;
const toggleActive = (item, activate = true) => {
item.statusItem = activate;
};
const handleClick = (item) => {
toggleActive(item);
setSelectedItems([...selectedItems]);
}
const enableAll = () => {
selectedItems.forEach(item => toggleActive(item, false));
setSelectedItems([...selectedItems]);
}
return (
<div className="current__events__wrapper">
{selectedItems.map((item, index) => (
<div className="current__events__hot-price__item" key={index}>
<div className={toggleActiveStyles(index)}>
<h5 className="current__events__card-title__large">Hot Price</h5>
</div>
<div className="current__events__image">
<img
src={item.avatar}
alt="user"
className="rounded-circle"
width="75"
height="75"
/>
</div>
<div className="current__events__info">
<h4 className="current__events__title__middle">{item.title}</h4>
</div>
<div className="current__events__timer">
<span>{minutes}</span>
<span>:</span>
<span>{seconds}</span>
</div>
<button
className={toggleActiveStylesBtns(index)}
onClick={() => handleClick(item)}
disabled={item.statusItem}
>
СДЕЛАТЬ ХОД
</button>
</div>
))}
</div>
);
};
export default CurrentEventsItem;
Если будут вопросы, то задавайте, объясню что и почему написал