Reputation: 21
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
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
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
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
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
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