'Update button text on click rendered using map method in ReactJS

I am rendering some data from array of object which contains button. I am appending button text from state which is set initially as "Select". What I want is when I click on any button then its value should get update as "Selected". Currently all button values are getting update when I click on any button.

const TestPage = () =>{
    let buttons = [
        {name:'Select1', id:1}, 
        {name:'Select2', id:2}, 
        {name:'Select3', id:3}
    ]
    
    const [btnText, setbtnText] = useState('Select')

    const handleClick = () =>{
        setbtnText('Selected')
    }
    return(
        <div>
            {!!buttons && buttons.map(item =>{
                return(
                    <p key={item.id}>
                        <Button btnType='button' btnText={btnText} clickHandler={handleClick} />
                    </p>
                )
            })}
        </div>
    )
}

export default TestPage;


Solution 1:[1]

Each button needs to have its own state. When you share one variable between multiple buttons, all will change if any handler changes the single variable.

const Example = () => {
  const [buttons, setButtons] = React.useState([
    {name: "Select", id: 1}, 
    {name: "Select", id: 2}, 
    {name: "Select", id: 3},
  ]);

  const handleButtonClick = i => {
    setButtons(prevState => {
      const nextState = prevState.map(btn => ({
        ...btn, name: "Select"
      }));
      nextState[i].name = "Selected";
      return nextState;
    });
  };

  return (
    <div>
      {buttons.map(({name, id}, i) => 
        <button
          key={id}
          onClick={() => handleButtonClick(i)}
       >
         {name}
       </button>
      )}
    </div>
  );
};

ReactDOM.render(<Example />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Another approach is to pass the id to the click handler and use const i = buttons.findIndex(btn => btn.id === id) to determine which button's name should be changed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1