Need help for loop in React

Viewed 73

I'm learning React, JS and I'm trying to use the .map method to display some data in an array. For each element in the array I create a button to show/hide a description with css and I'm looking for a way to only show the description of one element instead of all descriptions. It is probably unclear but here is the code :

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

export default function App() {
  const [showDescription, setshowDescription] = useState(false);
  const [anArray] = useState([
    { title: "First Div", description: "First description"},
    { title: "Antoher Div", description: "Another description"}
  ]);
  return (
    <div className="App">
      {anArray.map((val, index) => {
        return (
          <div className="div" key={index}>
            <div className="title">{val.title}</div>
            <button className="btn" onClick={() => setshowDescription(!showDescription)}>
              Show description
            </button>
            <div id={showDescription ? "display" : "hidden"}>
              <div className="description">{val.description}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

Do you have any idea please ?

3 Answers

Issue

You've a single boolean showDescription state that is toggling every description.

Solution

Store an index of the description you want to toggle. Use the index to match the currently mapped element. Conditionally render the description

export default function App() {
  const [showId, setShowId] = useState(null);

  // curried function to toggle to new index or back to null to hide
  const toggleDescription = id => () => setShowId(showId => showId === id ? null : id);

  const [anArray] = useState([
    { title: "First Div", description: "First description"},
    { title: "Antoher Div", description: "Another description"}
  ]);

  return (
    <div className="App">
      {anArray.map((val, index) => {
        return (
          <div className="div" key={index}>
            <div className="title">{val.title}</div>
            <button className="btn" onClick={toggleDescription(index)}> // <-- pass index
              Show description
            </button>
            {showId === index && ( // <-- check for index match
              <div> 
                <div className="description">{val.description}</div>
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

You can use index to show/hide your div. The issue is you are using only one Boolean value to handle it.

export default function App() {
  const [showDescriptionIndex, setshowDescriptionIndex] = useState(-1);
  const [anArray] = useState([
    { title: "First Div", description: "First description"},
    { title: "Antoher Div", description: "Another description"}
  ]);
  return (
    <div className="App">
      {anArray.map((val, index) => {
        return (
          <div className="div" key={index}>
            <div className="title">{val.title}</div>
            <button className="btn" onClick={() => setshowDescriptionIndex(index)}>
              Show description
            </button>
            <div id={showDescriptionIndex === index ? "display" : "hidden"}>
              <div className="description">{val.description}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

Try It

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

export default function App() {
  const [showDescription, setshowDescription] = useState({});
  const [anArray] = useState([
    { title: "First Div", description: "First description"},
    { title: "Antoher Div", description: "Another description"}
  ]);
  return (
    <div className="App">
      {anArray.map((val, index) => {
        return (
          <div className="div" key={index}>
            <div className="title">{val.title}</div>
            <button className="btn" onClick={() => setshowDescription({...showDescription, [index]: !showDescription[index]})}>
              Show description
            </button>
            <div id={showDescription && showDescription[index] ? "display" : "hidden"}>
              {showDescription[index]}
              <div className="description">{val.description}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

Tip: Use class="show/hide" instead of id="show/hide"

Related