i would like to change the button color, but i cant do it separately, i cant to use the color switch in every button one by one!
here is my code:
const [colorSwitch, setColorSwitch] = useState(true);
const slots = ['Slot 1', 'Slot 2'];
function SlotButton({ type, colorSwitch }: { type: string; colorSwitch: boolean }) {
return (
<Button
variant={colorSwitch ? 'contained' : 'outlined'}
style={{ width: 240, height: 100, borderRadius: 20, margin: 15 }}
onClick={() => {
setColorSwitch(!colorSwitch);
}}>
{type}
</Button>
);
}
return (
<MainSection>
<DrawerHeader />
<div>
<h1 style={{ color: 'white' }}>Dryer Module</h1>
</div>
<CardBox>
{slots.map((item) => {
return <SlotButton key={item} type={item} colorSwitch={colorSwitch}></SlotButton>;
})}
</CardBox>
</MainSection>
);
} ```
CodePudding user response:
You're currently using the same state variable (colorSwitch
) for both buttons, thus they will always have the same state/color. As soon as one button is clicked, the state/variable is updated and both buttons are being re-rendered with the same updated state/variable.
You need to create separate state variables if you want them to behave differently. In a simple component like this I would use a state object that contains the different variables/values. This is one way you could do that:
// object with properties instead of one variable
const [colorSwitchObj, setColorSwitchObj] = useState({
"Slot 1": true,
"Slot 2": true,
});
const slots = ['Slot 1', 'Slot 2'];
function SlotButton({ type, colorSwitch }: { type: string; colorSwitchObj: boolean }) {
return (
<Button
{ /* colorSwitchObj[type] accesses matching property */}
variant={colorSwitchObj[type] ? 'contained' : 'outlined'}
style={{ width: 240, height: 100, borderRadius: 20, margin: 15 }}
{ /* update by first copying the old state and then updating the specific value */}
onClick={() => {
setColorSwitchObj(...colorSwitchObj,
colorSwitchObj[type] = !colorSwitchObj[type]);
}}>
{type}
</Button>
);
}
const Main = () => {
//...
return (
<MainSection>
<DrawerHeader />
<div>
<h1 style={{ color: 'white' }}>Dryer Module</h1>
</div>
<CardBox>
{slots.map((item) => {
return <SlotButton key={item} type={item} colorSwitchObj={colorSwitchObj}></SlotButton>;
})}
</CardBox>
</MainSection>
);
}
When your components are simple like this it's usually fine to do it with a single useState
object. However, once you start working with larger objects in your state, it makes sense to look into & learn the useReducer
hook. Although this hook is slightly more complex, and takes a bit more effort to create, it can prevent many annoying state bugs because you get a much better organized way of maintaining your state.
CodePudding user response:
There is little need for mapping here. It would be far easier to group both buttons together in their own Component:
function SlotButtons(isSwitched) {
return (
<Button
variant={colorSwitch ? 'contained' : 'outlined'}
style={{ width: 240, height: 100, borderRadius: 20, margin: 15 }}
onClick={() => {
setColorSwitch(!colorSwitch);
}}>
{type}
</Button>
<Button
variant={!colorSwitch ? 'contained' : 'outlined'}
style={{ width: 240, height: 100, borderRadius: 20, margin: 15 }}
onClick={() => {
setColorSwitch(!colorSwitch);
}}>
{type}
</Button>
)
}
The second button reacts to inverted value of the first one. Or you could send both states to that component/