User
User

Reputation: 45

Need help for loop in React

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 ?

Upvotes: 3

Views: 85

Answers (3)

Surjeet Bhadauriya
Surjeet Bhadauriya

Reputation: 7156

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>
  );
}

Upvotes: 3

Drew Reese
Drew Reese

Reputation: 202648

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>
  );
}

Upvotes: 3

Zia ur Rehman
Zia ur Rehman

Reputation: 565

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"

Upvotes: 2

Related Questions