skip to Main Content

I am unfortunately a bit on the tube.
I have three buttons, to filter an array. By default the "All" Button should be active (with a red text-color). If you click on another button, the text-color of the clicked on should become red and the text-color of the others should become/stay grey. That’s my goal. But I can’t wrap my head around it! Hope somebody of you can help me out!

I tried it with this code. But all is does, it turn all buttons blue. How can I modify the code that only the clicked button becomes red text-colored?


export default function App() {
  const buttons = document.querySelectorAll(".btn");

  buttons.forEach((button, i) => {
    button.addEventListener("click", (e) => {
      if (parseInt(e.target.value) === i) {
        button.style.color = "red";
      }
      button.style.color = "blue";
    });
  });

  return (
    <>
      <button className="btn" value={0} style={{ color: "red" }}>
        Filter 1
      </button>
      <button className="btn" value={1}>
        Filter 2
      </button>
      <button className="btn" value={2}>
        Filter 3
      </button>
    </>
  );
}


2

Answers


  1. First of all, you should use the state management by React instead of trying to modify the DOM elements directly. If you use state in React, you can easily achieve that by assigning a custom state and an ID for each of your button, like so:

    const { Fragment, useState } = React;
    
    function App() {
      
      const [selectedBtn, setSelectedBtn] = useState(0);
    
      return (
        <Fragment>
          <button
            className="btn"
            onClick={() => setSelectedBtn(0)}
            style={{ color: selectedBtn === 0 ? 'red' : 'blue' }}
          >Filter 1
          </button>
          <button
            className="btn"
            onClick={() => setSelectedBtn(1)}
            style={{ color: selectedBtn === 1 ? 'red' : 'blue' }}
          >Filter 2
          </button>
          <button
            className="btn"
            onClick={() => setSelectedBtn(2)}
            style={{ color: selectedBtn === 2 ? 'red' : 'blue' }}
          >Filter 3
          </button>
        </Fragment>
      );
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById('react')
    );
    <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>

    In React, the App() function is the render function, it will be called everytime there’s any state changes (In this case every time setSelectedBtn is called), thus it will re-render all the buttons and have their color updated correctly.

    You can learn more about how it works in React’s documentation. Try to modify the sample code in the page to get a sense of how React works

    Login or Signup to reply.
  2. If you’re starting out with React AngVC’s answer is the best and quickest to understand – it covers state, and how to update that state when a click event is fired.

    I’m including this answer too as it deals with

    1. Maintain buttons as configuration (an array of objects) which is sometimes easier to manage at scale

    2. Using a separate (dumb) component for the button, and passing down props where necessary.

    3. Managing state in the parent component.

    const { useState } = React;
    
    // Pass in the button config to the parent component
    function Example({ btnConfig }) {
    
      // Initialise the state with it
      const [ buttons, setButtons ] = useState(btnConfig);
    
      // When a button is clicked...
      function handleClick(e) {
        
        // Grab the label from the button's dataset
        const { dataset: { label } } = e.target;
        
        // Iterate over the button state and return a
        // new array of updated button objects. If a button
        // label equals the label of the clicked button
        // set its "active" value to true, otherwise false
        const updated = buttons.map(button => {
          return {
            ...button,
            active: button.label === label ? true : false
          };
        });
    
        // Set the new state with the updated array
        setButtons(updated);
        
      }
    
      // Iterate over the buttons state to create
      // the buttons using the Button component
      // We pass down the label/active props from each
      // object as well as a reference to the click handler
      // defined above
      return (
        <div>
          {buttons.map(button => {
            const { label, active } = button;
            return (
              <Button
                label={label}
                active={active}
                handleClick={handleClick}
              />        
            );
          })}
        </div>
      );
    
    }
    
    // Build a button. It accepts some "props"
    // from which we can destructure the label/active values,
    // and the handler reference
    function Button(props) {
      
      const { label, active, handleClick } = props;
        
      // To set the style of the button we use an joined array.
      // We use a based "button" style, and add an "active" class
      // if the active prop value is true
      const buttonStyle = [
        'button',
        active && 'active'
      ].join(' ');
      
      // Return a button with a data attribute
      // for the label, the class name which uses the
      // buttonStyle string, and we attach the handler
      // reference to the button's click listener
      return (
        <button
          data-label={label}
          className={buttonStyle}
          type="button"
          onClick={handleClick}
        >{label}
        </button>
      );
    
    }
    
    // Define the button config
    const btnConfig = [
      { label: 'button1', active: true },
      { label: 'button2', active: false },
      { label: 'button3', active: false }
    ];
    
    // Pass the config in as a prop to the
    // Example component
    ReactDOM.render(
      <Example btnConfig={btnConfig} />,
      document.getElementById('react')
    );
    button { font-size: 1em; width: 100px; }
    button:not(:last-child) { margin-right: 0.25em; }
    button:hover { cursor: pointer; }
    .active { color: red; }
    <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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search