How to make only one button disabled on click in map method? With the help of the disabled hook, I have all pressed buttons . And how to make it so that after the timer expires the 'current__events__hot-price disabled' className changes back to 'current__events__hot-price'?
import { useEffect, useState } from 'react'
import './CurrentEventsItem.scss'
const CurrentEventsItem = () => {
const [timeLeft, setTimeLeft] = useState(5*60)
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 : setDisabled(false) || 5*60))
}, 1000)
return () => clearInterval(interval)
}, [])
const [appState, changeState] = useState({
objects: [
{id: 1, title: 'Apple iPhone 13 Pro Max 256Gb (небесно-голубой)', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
{id: 2, title: '500 Stars', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
{id: 3, title: 'Sony PlayStation 5 Digital Edition ', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false}
]
})
const toggleActive = (index) => {
let arrayCopy = [...appState.objects]
arrayCopy[index].statusItem
? (arrayCopy[index].statusItem = false)
: (arrayCopy[index].statusItem = true)
setDisabled(true)
changeState({...appState, objects: arrayCopy})
}
const toggleActiveStyles = (index) => {
if (appState.objects[index].statusItem) {
return 'current__events__hot-price disabled'
} else {
return 'current__events__hot-price'
}
}
const toggleActiveStylesBtns = (index) => {
if (appState.objects[index].statusItem) {
return 'current__events__btn-green disabled'
} else {
return 'current__events__btn-green'
}
}
const [disabled, setDisabled] = useState(false)
return (
<>
<div className='current__events__wrapper'>
{appState.objects.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(index)} disabled={disabled}>СДЕЛАТЬ ХОД</button>
</div>
)}
</div>
</>
)
}
export default CurrentEventsItem
CodePudding user response:
From what I can gather, you toggle one element's status by index and disable the button at that specific index. Instead of toggling the statusItem
property (a state mutation, BTW) you should just store the index of the "active" item.
Add an activeIndex
state that is null in its "inactive" state, and equal to an index when it is "active". The useEffect
hook should just instantiate the interval and the interval callback should just decrement the time left. Use a separate useEffect
hook with a dependency on the timeLeft
state to reset the activeIndex
and timeLeft
states. Disable the button element when the activeIndex
equals the mapped index. Pass the activeIndex
state to the CSS classname utility functions.
Example:
const CurrentEventsItem = () => {
const [activeIndex, setActiveIndex] = useState(null);
const [timeLeft, setTimeLeft] = useState(5*60);
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);
}, 1000);
return () => clearInterval(interval);
}, []);
const [appState, changeState] = useState({
objects: [
{id: 1, title: 'Apple iPhone 13 Pro Max 256Gb (небесно-голубой)', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
{id: 2, title: '500 Stars', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false},
{id: 3, title: 'Sony PlayStation 5 Digital Edition ', avatar: 'https://cdn-icons-png.flaticon.com/512/147/147144.png', statusItem: false}
]
});
const toggleActive = (index) => {
setActiveIndex(index);
};
useEffect(() => {
if (timeLeft <= 0) {
setActiveIndex(null);
setTimeLeft(5 * 60);
}
}, [setActiveIndex, setTimeLeft, timeLeft]);
const toggleActiveStyles = (index) => {
if (index === activeIndex) {
return 'current__events__hot-price disabled';
} else {
return 'current__events__hot-price';
}
};
const toggleActiveStylesBtns = (index) => {
if (index === activeIndex) {
return 'current__events__btn-green disabled';
} else {
return 'current__events__btn-green';
}
};
return (
<>
<div className='current__events__wrapper'>
{appState.objects.map((item, index) =>
<div className="current__events__hot-price__item" key={index}>
<div className={toggleActiveStyles(activeIndex)}>
<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(activeIndex)}
onClick={() => toggleActive(index)}
disabled={activeIndex === index}
>
СДЕЛАТЬ ХОД
</button>
</div>
)}
</div>
</>
);
}
export default CurrentEventsItem