CheesyMonkey
CheesyMonkey

Reputation: 21

How to open one instead of all divs created using .map()

I am rendering <div>’s of info through .map() over an array, and have a button next to each that

onClick={() => setShow(!show)}

so basically just opens and closes the div showing the info. What happens at the moment it clicking the button next to any div opens all the div info components, where as I’m trying to simply open the div where the button was clicked. Here’s a snippet:

const [show, setShow] = React.useState(false)
Const Info = () => {
Return ( 
...
news.map(info => {
<>
... div of info (only shown when show === true) 
<button onClick={() = setShow(!show)}
</>
}
)
}

Any advice would be greatly appreciate, sorry for the terrible grammar / layout (doing this on my phone)

Upvotes: 2

Views: 1093

Answers (5)

Atamyrat
Atamyrat

Reputation: 1

import React, { useState } from 'react';

const MyComponent = () => {
  const [activeDiv, setActiveDiv] = useState(null);

  const items = ['Item 1', 'Item 2', 'Item 3']; // Your items to map over

  const toggleDiv = (index) => {
    setActiveDiv(index === activeDiv ? null : index);
  };

  return (
    <div>
      {items.map((item, index) => (
        <div key={index} onClick={() => toggleDiv(index)}>
          <h2>{item}</h2>
          {activeDiv === index && (
            <p>This is the content of {item}. Click to collapse/expand.</p>
          )}
        </div>
      ))}
    </div>
  );
};

export default MyComponent;

Upvotes: 0

Banny
Banny

Reputation: 111

**Hope this works for you**

 

const [show, setShow] = React.useState(false)
    Const Info = () => {
      Return ( 
      ...
     news.map(info => {
     <div show={show}>
     ... div of info (only shown when show === true) 
     </div>
    } 
    <button onClick={() = setShow(!show)}>Show</button>
    <button onClick={() = setShow(show)}>Hide</button>
     )
    }

Upvotes: 2

Fahad Shinwari
Fahad Shinwari

Reputation: 968

First things first it will be good if you make an array which also has the show property. At first let show be false. Since you are using functional component.The content is there too.

const [items, setItems] = useState([
    { id: 1, name: "ahmad", content: "hi this is ahmad", show: false },
    { id: 2, name: "zahid", content: "hi this is zahid", show: false }
  ]);

Second step will be to map through the array. The name is shown inside h1 and items content is shown based on the property show basically used a ternary operator. Passed a handleShow function on the onClick.

const renderContent = items.map((item) => {
    return (
      <>
        <h1>{item.name}</h1>
        {item.show ? <p>{item.content}</p> : null}
        <button onClick={() => handleShow(item.id)}>Click</button>
      </>
    );
  });

    return
     <div className="App">
         {renderContent}
     </div>;

Third step is to work on the handleShow function. Id of the object is passed as a parameter. We will first find the object index based on the id. and then change the show property to the opposite. From false to and vice versa.

const handleShow = (id) => {
    const elementsIndex = items.findIndex((element) => element.id === id);
    let newArray = [...items];
    newArray[elementsIndex] = {
      ...newArray[elementsIndex],
      show: !newArray[elementsIndex].show
    };

    setItems(newArray);
  };

Live Link : https://codesandbox.io/s/muddy-firefly-yc7jb?file=/src/App.js:287-566

Upvotes: 1

akhtarvahid
akhtarvahid

Reputation: 9769

Check this example, it will help you to create your own.

 export default class App extends React.Component {
  state = {
    lists: array,
    oIndex: null,
    iIndex: null
  };
  handleTile = (index) => {
    this.setState({ oIndex: index });
  };

  render() {
    const { oIndex, lists } = this.state;
    return (
      <>
        {lists.map((ar, index) => (
          <div
            className="heading"
            key={index}
            onClick={() => this.handleTile(index)}>
             <div className={oIndex === index ? "tile is-active" : "tile"}>
              <div className="left">
              <div>{`Menu ${index}`}</div>
              </div>
             </div>

            {oIndex === index ? (
              <React.Fragment>
                <h1>{index}: Content body</h1>
              </React.Fragment>
            ) : null}
          </div>
        ))}
      </>
    );
  }
}

Live working demo

Upvotes: 1

Ran Marciano
Ran Marciano

Reputation: 1531

You can either separate the button and the div to another component (which will have the "show" state) or you can give each div and button and Id and use it to indicate which button triggers which div

Upvotes: 0

Related Questions