2

I'm trying to change the color of a button from gray to blue when it gets clicked, and also change the color of the previously selected button back to gray, so only the current selected button is blue. However, the buttons are generated using the map() method, so with useState I get all buttons to change color at the same time:

codesandbox

import React, {useState } from "react";
import "./styles.css";

export default function App() {
  const menuItems = ["day 1", "day 2", "day 3"]
  const [active, setActive] = useState(false);
 
 return (
   <nav>
     {menuItems.map((days, idx) => {
       return (
         <button
           key={days}
           onClick={() => {
             setActive(!active)
           }}
           style={{backgroundColor: active? "blue" : ""}}
         >
           {days}
         </button>
       );
     })}
   </nav>
 );
};

4 Answers 4

3

A possible solution is to store the currently selected button's name (or some Id) in the state.

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const menuItems = ["day 1", "day 2", "day 3"];
  const [activeButton, setActiveButton] = useState('');

  return (
    <nav>
      {menuItems.map((days, idx) => {
        return (
          <button
            key={days}
            onClick={() => {
              setActiveButton(days);
            }}
            style={{ backgroundColor: activeButton === days ? "blue" : "" }}
          >
            {days}
          </button>
        );
      })}
    </nav>
  );
}

Make sure your buttons have different names (as they are already now) for this to work and also because you're passing them in the key prop. If you think more than one button could have the same names in the future, add an id field too.

const menuItems = [{id: 1, name: "day 1"}, {id: 2, name: "day 2"}, {id: 3, name: "day 3"}];

Update the code accordingly. It won't be a good idea to pass array index in the key prop, if the situation changes. So, the id field will come in handy.

Sign up to request clarification or add additional context in comments.

Comments

3

You can change your active state from a bool to a number and set it to the index of the selected button

const [active, setActive] = useState(null);

And change your click event

 onClick={() => {
     setActive(idx)
 }}

And change your class condition to this

style={{backgroundColor: active === idx ? "blue" : ""}}

Comments

0

You should do this way:

export default function App() {
  const menuItems = ["day 1", "day 2", "day 3"];
  const [active, setActive] = useState(0); 

  return (
    <nav>
      {menuItems.map((days, idx) => {
        return (
          <button
            key={days}
            onClick={() => {
              setActive(idx);
            }}
            style={{ backgroundColor: idx===active ? "blue" : "" }}
          >
            {days}
          </button>
        );
      })}
    </nav>
  );
}

In this case, you selected index key

Comments

0

Currently, the state active will get toggled no matter which button you're firing, so you'll be changing the state that every button depends on.

One of the ways for you to solve this problem would be for you to create a button component that has the state action, by doing this each state will belong to the instance of the component.

Once you created your component, map the component instead and pass in the props you need

export default function App() {
  const menuItems = ["day 1", "day 2", "day 3"];

  return menuItems.map((day, idx) => <Button key={idx} day={day} />);
}

function Button({ day }) {
  const [active, setActive] = useState(false);
  return (
    <button
      style={{ backgroundColor: active ? "blue" : "" }}
      onClick={() => setActive(!active)}
    >
      {day}
    </button>
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.