So I'm losing my mind over here trying to essentially just select the sibling element of things that are mapped.
I basically map over an object from an API, grab some stuff from it, and display some text and an ul with some li in it. I ultimately want to click on h2 and have it alter the ul below it. In this case, I want the ul item below it to have a display of none until clicked. I also tried returning the JSX of the ul in the onClick of the h2 tag, but it didn't add any elements to the page.
This wouldn't be so bad if I knew what anything was going to be, and it was a set object, but being an API, I could have 1 or 1000 ul to work with that all need the same functionality. I was reading to do it by state, but I don't know how many items there are going to be, so how would I set state on an undefined number of items? Also, wouldn't having 100 states for this be crazy if that's what my API returned??
return myData.map((obj) => (
<div style={{ maxWidth: "500px", marginLeft: "25%" }} key={obj.name}>
<img
src={obj.image}
width="500px"
></img>
<h1>{obj.name}</h1>
<h2 id={'ingredients' Math.Random} onClick={(e) => {console.log(e)}}>Ingredients</h2>
<ul id={'UL' Math.random()}>
{obj.ingredients.map((index) => (
<ListItem key={"ingredients" Math.random()} value={index} />
))}
</ul>
Side note - this code is ultimately for my practice only, so ignore bad naming etc...
CodePudding user response:
You can achieve this by only using one state. Assuming your obj.name
is unique since you are using it as a key
value. You can use this name to determine wheter or not to display your ul
, if the id is in the array then display the ul
, if not do not display.
const YourComponent = () => {
// state to track all the ids of all the expanded ul's
const [expandedIds, setExpandedIds] = useState([]);
const toggleVisibility = (idToToggle) => {
// set new state
setExpandedIds((prevIds) => {
// if the id to toggle is in the array, if not add it
if (!expandedIds.includes(idToToggle)) return [...prevIds, idToToggle];
// else remove the id
return prevIds.filter((id) => id !== idToToggle);
});
};
return myData.map((obj) => (
<div style={{ maxWidth: "500px", marginLeft: "25%" }} key={obj.name}>
<img src={obj.image} width="500px"></img>
<h1>{obj.name}</h1>
<h2 onClick={() => toggleVisibility(obj.name)}>Ingredients</h2>
{expandedIds.includes(obj.name) && (
<ul id={"UL" Math.random()}>
{obj.ingredients.map((index) => (
<ListItem key={"ingredients" Math.random()} value={index} />
))}
</ul>
)}
</div>
));
};
I hope this helps you with your project.