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

Viewed 648

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)

4 Answers
**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>
     )
    }

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

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

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

Related