Reputation: 311
Hello I'm trying to make a sidebar menu using material ui
This sidebar menu contain categories and there sub categories.
I have code this:
What I'm trying to make ?
I take some categories data from my Laravel API, on each categories they can have an object of sub categories, and I collapse this to show the sub categories from the parent category
If I collapse one every one collapse, this is normal because they share the same state, but I don't know how to make one state for each parent categories
const categoriesList = this.state.categories.map((item, k) => {
return (
<React.Fragment key={k}>
<ListItem button onClick={this.handleClick}>
<ListItemText primary={item.label} />
{item.category !== null ? this.state.open ? <ExpandLess /> : <ExpandMore /> : null}
</ListItem>
{item.category !== null ? <>
<Collapse in={this.state.open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{item.category.map((ite,l) => <ListItem key={l} button className={classes.nested}><ListItemText primary={ite.label} /></ListItem>)}
</List>
</Collapse>
</> : null}
</React.Fragment>
)
})
``
Upvotes: 0
Views: 4336
Reputation: 311
This is my parent component with hook
first time I use hooks
import React, {useState} from 'react';
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import Collapse from "@material-ui/core/Collapse";
import List from "@material-ui/core/List";
export function Category(props){
const [open, setOpen] = useState(false);
let handleClick = () => {
setOpen(!open)
}
return (
<React.Fragment key={props.id}>
<ListItem button onClick={handleClick}>
<ListItemText primary={props.categorie.label} />
{props.category !== null ? open ? <ExpandLess /> : <ExpandMore /> : null}
</ListItem>
{props.category !== null ? <>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{props.category.map((ite,l) => <ListItem key={l} button className={props.classes.nested}><ListItemText primary={ite.label} /></ListItem>)}
</List>
</Collapse>
</> : null}
</React.Fragment>
)
}
Upvotes: 0
Reputation: 4218
I would recommend that you create a component for each category. So instead you would have:
const categoriesList = this.state.categories.map((item, k) => {
return <Category key={k} {...item} />;
});
And elsewhere in your code you'd have another Component:
const Category = (props) => {
const [open, setOpen] = useState(false);
function handleClick(e) { ... }
return (
<React.Fragment>
<ListItem button onClick={handleClick}>
<ListItemText primary={props.label} />
{props.category !== null ? open ? <ExpandLess /> : <ExpandMore /> : null}
</ListItem>
{item.category !== null ? <>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{props.category.map((ite,l) => <ListItem key={l} button className={classes.nested}><ListItemText primary={ite.label} /></ListItem>)}
</List>
</Collapse>
</> : null}
</React.Fragment>
);
}
Then the state is contained with the Category component, and you can keep your container component simple.
[note] I prefer function components, so used that here, but a Class Component wouldn't change this answer.
Upvotes: 2