Md Amir Sohail
Md Amir Sohail

Reputation: 65

how to add class and remove class from buttons in react?

I have 20 buttons and I wanted to apply class .active on the button which is clicked and the rest will inactive. Suppose I clicked on button one then I want to add an active class to button one and then when I clicked on button two then button two will get an active class and active class removed from button one.

import React from "react";
const PaginationButtonsList = (props) => {

    const handleClick = (event) =>{
   
    }
  return (
    <div className="pagination-buttons-list">
      <button onClick={handleClick} id="button-1">1</button>
      <button onClick={handleClick} id="button-2">2</button>
      <button onClick={handleClick} id="button-3">3</button>
      <button onClick={handleClick} id="button-4">4</button>
      <button onClick={handleClick} id="button-5">5</button>
      <button onClick={handleClick} id="button-6">6</button>
      <button onClick={handleClick} id="button-7">7</button>
      <button onClick={handleClick} id="button-8">8</button>
      <button onClick={handleClick} id="button-9">9</button>
      <button onClick={handleClick} id="button-10">10</button>
      <button onClick={handleClick} id="button-11">11</button>
      <button onClick={handleClick} id="button-12">12</button>
      <button onClick={handleClick} id="button-13">13</button>
      <button onClick={handleClick} id="button-14">14</button>
      <button onClick={handleClick} id="button-15">15</button>
      <button onClick={handleClick} id="button-16">16</button>
      <button onClick={handleClick} id="button-17">17</button>
      <button onClick={handleClick} id="button-18">18</button>
      <button onClick={handleClick} id="button-19">19</button>
      <button onClick={handleClick} id="button-20">20</button>
    </div>
  );
};

export { PaginationButtonsList };

Upvotes: 0

Views: 1385

Answers (4)

Nemanja2912
Nemanja2912

Reputation: 510

I assume that you don't want a button with just generic numbers for text. So you will need to:

  1. create an array list with all text that you want to set to the button
  2. Then render all of it through the map and bind the onClick event to take the index
  3. on click you should set that index in state and check which button has that index so set it to active

.

import React, {useState} from "react";

/* Change this number to any text and add as many as you need */
let buttonText = ['1','2','3','4','5']

const PaginationButtonsList = (props) => {
    const [activeIndex, setActiveIndex] = useState(-1)

    const handleClick = (value) =>{
           setActiveIndex(value)   
    }
  return (
    <div className="pagination-buttons-list">
      {buttonText.map((text,index)=> (
           <button onClick={()=>handleClick(index)} class={index === activeIndex ? "active" :""} id={`button-${index}`}>{text}</button>
        )
    </div>
  );
};

export { PaginationButtonsList };

Upvotes: 3

Mulan
Mulan

Reputation: 135237

You only need to save a single integer of state, the index corresponding to the active button -

function App({ buttons = [] }) {
  const [active, setActive] = React.useState(-1)
  const toggle = index => event => setActive(index)
  return <div>
    {buttons.map((b, key) =>
       <button
         className={active == key && 'active'}
         onClick={toggle(key)}
         children={b}
       />
    )}
  </div>
}

ReactDOM.render(
  <App buttons={["🍟","🥨","🍐","🌮","🥤"]} />,
  document.body
)
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>

If you want repeated clicks to the same button to toggle the active off, if the same button is clicked twice, you can restore the initial active state of -1 -

function App({ buttons = [] }) {
  const [active, setActive] = React.useState(-1)
  const toggle = index => event =>
    setActive(index == active ? -1 : index) // <-
  return <div>
    {buttons.map((b, key) =>
       <button
         className={active == key && 'active'}
         onClick={toggle(key)}
         children={b}
       />
    )}
  </div>
}

ReactDOM.render(
  <App buttons={["🍟","🥨","🍐","🌮","🥤"]} />,
  document.body
)
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>

Upvotes: 0

Andy
Andy

Reputation: 63524

One way of approaching this would be to create an array of button objects that you can use to configure your component. Each button object in the array would have the shape { id: number, text: string, active: boolean } that defines it. You can that add that configuration to state.

When a button is clicked you reset the active values of each button (by updating a deep-copy the current state), update the active value of the clicked button, and finally create a new state with the updated data. That new state will be reflected in the component when it's re-rendered.

This method also has the advantages that 1) you encapsulate the button config in one place without the need for separate states, and 2) you don't need to hard-code all the buttons in the JSX - you can map over the button configuration to create an array of buttons using a useful Button component.

const { useState } = React;

// Pass in the button config
function Example({ btnConfig }) {

  // Set state with the config
  const [ btns, setBtns ] = useState(btnConfig);

  // When a button is clicked grab its id from its dataset,
  // make a deep copy of the state resetting all of the active
  // values for each button to false, find the index of the button
  // that was clicked, and then set its active value to true.
  // Finally update the state to re-render the component
  function handleClick(e) {
    const { id } = e.target.dataset;
    const reset = btns.map(btn => ({ ...btn, active: false }));
    const index = reset.findIndex(btn => btn.id === +id);
    reset[index].active = true;
    setBtns(reset);
  }

  // `map` over the state and create JSX using a 
  // Button component passing down the properties from
  // the objects in state as well as a reference to the
  // `handleClick` function
  return (
    <div>
      {btns.map(btn => {
        const { id, text, active } = btn;
        return (
          <Button
            key={id}
            id={id}
            active={active}
            text={text}
            handleClick={handleClick}
          />
        );
      })}
    </div>
  );

}

// Accepts the button props and returns a button. If
// the active value is true then apply the "active" class
function Button({ id, text, active, handleClick }) {
  return (
    <button
      data-id={id}
      onClick={handleClick}
      className={active && 'active'}
    >{text}
    </button>
  );
}

// Create a button config - an array of button of objects
const btnConfig = Array.from({length: 10}, (_, i) => {
  const id = i + 1;
  return { id, text: id, active: false }; 
});

// Pass in the button config to the component
ReactDOM.render(
  <Example btnConfig={btnConfig} />,
  document.getElementById('react')
);
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<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="react"></div>

Upvotes: 0

jsejcksn
jsejcksn

Reputation: 33749

You can create an array state holding information for each button.

In each button state object in the array, include a property for whether the button is active or not. Then use this property when mapping the button states to actual buttons and set the active class if the button's state is active.

When a button is clicked, update the state array: make that button's state active and make every other button's state inactive.

Here's a complete example with types:

import {default as React, type ReactElement, useState} from 'react';

type ButtonState = {
  active: boolean;
  id: number;
};

const PaginationButtonsList = () => {
  const [buttonStates, setButtonStates] = useState<ButtonState[]>(Array.from(
    {length: 20},
    (_, i) => ({id: i + 1, active: false}),
  ));

  const createButtonFromState = (
    {active, id}: ButtonState,
    index: number,
  ): ReactElement => {
    const setActiveExclusive = () => {
      setButtonStates(arr => arr.map((state, i) => ({
        ...state,
        active: i === index,
      })));
    };

    const buttonProps = {
      className: active ? 'active' : '',
      id: `button-${id}`,
      key: id,
      onClick: setActiveExclusive,
    };

    return (<button {...buttonProps}>{id}</button>);
  };

  return (
    <div className="pagination-buttons-list">
      {buttonStates.map(createButtonFromState)}
    </div>
  );
};

Code in the TypeScript Playground

Upvotes: -1

Related Questions