Rexhep Rexhepi
Rexhep Rexhepi

Reputation: 137

React - toggle class: useState hook form several button

I have some buttons and I'm trying to add active class for clicked button. But when I click one of the buttons, all buttons are getting active class.

const { useState } = React;
const { render } = ReactDOM;
const node = document.getElementById("root");

const Button = ({ message }) => {
  const [condition, setCondition] = useState(false);
  return (
    <div>
    {
    Object.keys(res).map((data) => (
    <Button className={condition ? "button toggled" : "button"} onClick=. 
     {() => {
      setCondition(!condition)}
     }}
     ))
      }
    </div>
  );
   //Updated
   Object.keys(res).map((data) => (
    <Button className={condition ? "button toggled" : "button"} onClick=. 
     {() => {
      setCondition(condition === "off" ? "on" : "off")}
     }}
     ))
      }
    </div>
  ); //This can be modified to work for button clicked. Because active class is added to all buttons, if one of them is clicked
};
render(<Button message="Click me if you dare!" />, node);

This is working if I click the first button, but if I click again the same button, this active class should be removed

Upvotes: 1

Views: 7970

Answers (5)

Gaurav Mogha
Gaurav Mogha

Reputation: 400

import React, {useState, useCallback} from "react";

const defaultButtons = [
    {id: 1},
    {id: 2},
    {id: 3},
    {id: 4}
];

export default function App() {
    const [toggledButtonId, setToggledButtonId] = useState(false);

    function toggleButton(button) {
        setToggledButtonId(button.id);
    }
      const toggleButton = useCallback((id) => setToggledButtonId(state => id), [toggledButtonId]);

    return (
        <div>
            {defaultButtons.map(button => {
                const isToggled = button.id === toggledButtonId;
                return (
                    <button
                        key={button.id}
                        className={isToggled ? "toggledButtonId toggled" : "toggledButtonId"}
                        onClick={toggleButton(button.id)}>
                        {String(isToggled)}
                    </button>
                )
            })}
        </div>
    )
}

Upvotes: 0

dm.shpak
dm.shpak

Reputation: 355

You could create component Button with state within and use this component to populate buttons. Probably you can use :active CSS selector and avoid js at all

Upvotes: 0

Arnaud Claudel
Arnaud Claudel

Reputation: 3138

Here is a very naive solution, but it will help you understand the problem.

If you're on a real project, I suggest you to use an existing library (that can be found by searching react toggle button group)

import React, {useState} from "react";

const defaultButtons = [
    {id: 1},
    {id: 2},
    {id: 3},
    {id: 4}
];

export default function App() {
    const [toggledButtonId, setToggledButtonId] = useState(null);

    function toggleButton(button) {
        setToggledButtonId(button.id);
    }

    return (
        <div>
            {defaultButtons.map(button => {
                const isToggled = button.id === toggledButtonId;
                return (
                    <button
                        key={button.id}
                        className={isToggled ? "toggledButtonId toggled" : "toggledButtonId"}
                        onClick={() => toggleButton(button)}>
                        {String(isToggled)}
                    </button>
                )
            })}
        </div>
    )
}

Upvotes: 2

katamaster818
katamaster818

Reputation: 341

You need to use a seperate state handler for each button:

const Button = ({ message }) => {
 const [condition, setCondition] = useState(false);
 const [condition2, setCondition2] = useState(false);
  return (
    <div>
    <div
      onClick={() => setCondition(!condition)}
      className={condition ? "button toggled" : "button"}
    >
      {message}
    </div>  
      <div
      onClick={() => setCondition(!condition2)}
      className={condition2 ? "button toggled" : "button"}
    >
      {message}
    </div>  
    </div>
  );
};

render(<Button message="Click me if you dare!" />, node);

Upvotes: 0

Related Questions