Home > Blockchain >  React, how can i change the button colors separately in every buttons?
React, how can i change the button colors separately in every buttons?

Time:02-22

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/

  • Related