Home > Back-end >  React: how to use spread operator in a function that toggles states?
React: how to use spread operator in a function that toggles states?

Time:10-13

I made an example of my question here: EXAMPLE

I'm mapping an array of objects that have a button that toggles on click, but when clicking on the button every object is changed.

This is the code

export default function App() {
  const [toggleButton, setToggleButton] = useState(true);

  // SHOW AND HIDE FUNCTION
  const handleClick = () => {
    setToggleButton(!toggleButton);
  };

  return (
    <div className="App">
      <h1>SONGS</h1>
      <div className="container">
        {/* MAPPING THE ARRAY */}
        {songs.map((song) => {
          return (
            <div className="song-container" key={song.id}>
              <h4>{song.name}</h4>
              {/* ON CLICK EVENT: SHOW AND HIDE BUTTONS */}
              {toggleButton ? (
                <button onClick={handleClick}>PLAY</button>
              ) : (
                <button onClick={handleClick}>STOP</button>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

I know I should be using spread operator, but I couldn't get it work as I spected.

Help please!

CodePudding user response:

Of course every object will change because you need to keep track of toggled state for each button. Here is one way to do it:

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

const songs = [
  {
    name: "Song A",
    id: "s1"
  },
  {
    name: "Song B",
    id: "s2"
  },
  {
    name: "Song C",
    id: "s3"
  }
];

export default function App() {
  const [toggled, setToggled] = useState([]);

  const handleClick = (id) => {
    setToggled(
      toggled.indexOf(id) === -1
        ? [...toggled, id]
        : toggled.filter((x) => x !== id)
    );
  };
  return (
    <div className="App">
      <h1>SONGS</h1>
      <div className="container">
        {songs.map((song) => {
          return (
            <div className="song-container" key={song.id}>
              <h4>{song.name}</h4>
              {toggled.indexOf(song.id) === -1 ? (
                <button onClick={() => handleClick(song.id)}>PLAY</button>
              ) : (
                <button onClick={() => handleClick(song.id)}>STOP</button>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

There are many ways to do it. Here, if an id is in the array it means that button was toggled. You can also keep ids of toggled buttons in object for faster lookup.

CodePudding user response:

One way of handling this requirement is to hold local data into states within the Component itself.

I have created a new Button Component and manages the toggling effect there only. I have lifted the state and handleClick method to Button component where it makes more sense.

const Button = () => {
  const [toggleButton, setToggleButton] = useState(true);
  const click = () => {
    setToggleButton((prevValue) => !prevValue);
  };

  return <button onClick={click}>{toggleButton ? "Play" : "Stop"}</button>;
};

Working Example - Codesandbox Link

  • Related