I am learning react and I have stumbled upon a problem that I am trying to solve for several hours now but without any luck. I have an array of product sizes which I map to buttons. My goal is to change the state only of the last clicked button and to pass the value of the button to a variable. Currently whenever clicked, all buttons change their state.
import React, { useState } from "react";
export default function Button() {
const sizes = [10, 11, 12, 13];
const [btnState, setBtnState] = useState(true);
const handleClick = () => setBtnState(!btnState);
return (
<div className="button-component">
{sizes.map((size, index) => (
<button className="btn" onClick={handleClick}>
{size} {btnState.toString()}
</button>
))}
</div>
);
}
CodePudding user response:
Issue
The issue here is that there is only the single state value and all the mapped buttons use the same state in the same way.
Solution
Convert the btnState
to an object where the size
is a dynamic key.
function Button() {
const sizes = [10, 11, 12, 13];
const [btnState, setBtnState] = useState({});
const handleClick = (size) => () => setBtnState(sizes => ({
...size,
[size]: !sizes[size]
}));
return (
<div className="button-component">
{sizes.map((size, index) => (
<button className="btn" onClick={handleClick(size)}>
{size} {String(!!btnState[size])}
</button>
))}
</div>
);
}
If you want only a single active state then store just the passed size
in the callback handler in state and check it's value when mapping.
function Button() {
const sizes = [10, 11, 12, 13];
const [btnState, setBtnState] = useState();
const handleClick = (size) => () =>
setBtnState(size);
return (
<div className="button-component">
{sizes.map((size, index) => (
<button className="btn" onClick={handleClick(size)}>
{size} {String(btnState === size)}
</button>
))}
</div>
);
}