简体   繁体   中英

How to Use React Toggle Inside Map Function

I'm trying to use a toggle inside of a map function. I thought I had it, but there's clearly something wrong with my logic. When I click on some of the toggle items within the map, I have to click on them twice in order to see the change. It seems to happen when I toggle one item to true, then immediately toggle another item to true. Thanks in advance for any help.

Here's the CodeSandbox: https://codesandbox.io/s/nice-hertz-srgew

And the code:

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./styles.css";

export default function App() {
  const [people, setPeople] = useState([]);
  const [prodToggle, setProdToggle] = useState(false);
  const [partToggle, setPartToggle] = useState(false);

  useEffect(() => {
    axios.get("./data.json").then((res) => {
      setPeople(res.data.people);
    });
  }, []);

  const onAddProdSelect = () => {
    const updatedProdToggle = !prodToggle;
    setProdToggle(updatedProdToggle);
  };

  const onAddPartSelect = (i) => {
    const updatedToggle = !partToggle;
    setPartToggle(updatedToggle);
    const updatedData = people.map((item, idx) => {
      if (idx === i) {
        return {
          ...item,
          itemPartToggle: updatedToggle
        };
      }
      return item;
    });
    setPeople(updatedData);
  };

  return (
    <main>
      <div onClick={() => onAddProdSelect()}>
        <p>{prodToggle ? "Red" : "Blue"}</p>
      </div>
      {people.map((person, i) => (
        <div onClick={() => onAddPartSelect(i)} key={i}>
          <p>{person.itemPartToggle ? person.name : person.age}</p>
        </div>
      ))}
    </main>
  );
}

Your issue is that you're sharing the one toggle state with all of your person objects by having the partToggle state. Instead, keep the toggle state on each object (like you are currently doing with itemPartToggle ), and use that to determine what the toggle value should change to for that particular object that you clicked on:

const onAddPartSelect = (i) => {
    const updatedData = people.map((item, idx) => {
      if (idx === i) {
        return {
          ...item,
          itemPartToggle: !item.itemPartToggle // use the flipped version of the current toggle state for the current item
        };
      }
      return item;
    });
    setPeople(updatedData);
};

See example below:

 const { useState, useEffect } = React; function App() { const [people, setPeople] = useState([{"id":"1","name":"Bob","age":"21"},{"id":"2","name":"Ed","age":"45"},{"id":"3","name":"Mary","age":"32"},{"id":"4","name":"Tom","age":"76"}]); // hardcoding data for example const [prodToggle, setProdToggle] = useState(false); const onAddProdSelect = () => { const updatedProdToggle =;prodToggle; setProdToggle(updatedProdToggle); }. const onAddPartSelect = (i) => { const updatedData = people,map((item. idx) => { if (idx === i) { return {..,item: itemPartToggle. ;item;itemPartToggle }; } return item; }); setPeople(updatedData)? }: return ( <main> <div onClick={() => onAddProdSelect()}> <p>{prodToggle. "Red", "Blue"}</p> </div> {people.map((person? i) => ( <div onClick={() => onAddPartSelect(i)} key={i}> <p>{person.itemPartToggle: person.name; person.age}</p> </div> ))} </main> ), } ReactDOM.render(<App />; document.body);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM