I’m trying to change an inline style property of several items that have position info stored in a useState hook as well on the style property of each item rendered. I wanted to change the CSS value of all the items except the one I clicked on. I devised a function to do so, however when I try to update the CSS value using setState, the items don’t re-render and I get an error saying “discs.map is not a function”. Am I using the set state hook correctly? Should i be using the setState hook for a task like this i.e animating position of items?
// Main Component
function App() {
const [discs, setDiscs] = useState([
{ id: 1, top: 100 },
{ id: 2, top: 200 },
{ id: 3, top: 300 },
{ id: 4, top: 400 },
{ id: 5, top: 500 },
{ id: 6, top: 600 },
{ id: 7, top: 700 },
{ id: 8, top: 800 },
{ id: 9, top: 900 },
{ id: 10, top: 1000 },
{ id: 11, top: 1100 },
{ id: 12, top: 1300 }
])
function enlargeDisc(e, num) {
let t = e.target
if (t.classList.contains('active')) {
t.classList.remove('active')
adjustDiscPos(num, true)
} else {
t.classList.add('active')
adjustDiscPos(num, false)
}
}
function adjustDiscPos(n, backToOriginal) {
console.log(discs)
discs.forEach((disc) => {
if (disc.id < n) {
setDiscs(prevState => backToOriginal ? prevState + 300 : prevState - 300)
}
if (disc.id > n) {
setDiscs(prevState => backToOriginal ? prevState - 300 : prevState + 300)
}
})
}
return (
<div className="App">
<div className="container">
<div className="wrapper" style={{bottom: scroll}}>
{discs.map((item) => (
<div className ='disc' key={item.id} data-index={item.id} style={{top: item.top + 'px'}} onClick={(e)=> enlargeDisc(e, item.id)} ></div>
))}
</div>
</div>
</div>
);
}
export default App;
CSS
.disc {
position: absolute;
transform:
translate(-50%, -50%) rotateX(90deg) scale(1);
width: 10em;
height: 10em;
transform-style: preserve-3d;
cursor: pointer;
background-image:
radial-gradient(rgba(0, 0, 0, 0), rgb(22, 22, 22) 95%),
url('./img/cd3.png');
background-size: 100% 100%;
transition: all 0.5s ease-in-out;
}
.disc.active {
transform:
translate(-50%, -50%) rotateX(0deg) scale(1.5);
}
Advertisement
Answer
I am assuming here that it is the value of top you wish to manipulate. I am also assuming that you wish to leave the disc with id equal to n as it is. Correct me if I’m wrong.
What you need to do is to create a temporary array and add the new values to that array. Then, when that is done, you call setDiscs with the temporary array as an argument.
let tmp_discs = [];
discs.forEach((disc) => {
if (disc.id < n) {
tmp_discs[disc.id] = backToOriginal ? disc.top + 300 : disc.top - 300;
} else if (disc.id > n) {
tmp_discs[disc.id] = backToOriginal ? disc.top - 300 : disc.top + 300;
} else {
tmp_discs[disc.id] = disc.top;
}
})
setDiscs(tmp_discs);