问题
I found what i need on this link https://material-ui.com/components/lists/#simple-list using material-ui. On this link there is chapter "Nested list items". This chapter have only one nested list item with method for expand more/less. I have two nested items in my sidebar. Both of them call a method handleClick for expand more/less options. I want to expand only one (clicked) nested item per click. I also want to expand less on previous item. Here is my sidebar:
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Collapse from "@material-ui/core/Collapse";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import HomeIcon from '@material-ui/icons/Home';
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
import AccessibilityNewIcon from '@material-ui/icons/AccessibilityNew';
import VisibilityIcon from '@material-ui/icons/Visibility';
import AddIcon from '@material-ui/icons/Add';
const drawerWidth = 260;
const useStyles = makeStyles((theme) => ({
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
drawerContainer: {
overflow: "auto",
},
root: {
width: "100%",
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
nested: {
paddingLeft: theme.spacing(4),
},
}));
export default function SideBar() {
const classes = useStyles();
const [open, setOpen] = React.useState(true);
const handleClick = () => {
setOpen(!open);
};
return (
<Drawer
className={classes.drawer}
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
>
<Toolbar />
<div className={classes.drawerContainer}>
<List
component="nav"
aria-labelledby="nested-list-subheader"
className={classes.root}
>
<ListItem button>
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText primary="Home" />
</ListItem>
<ListItem button onClick={handleClick}>
<ListItemIcon>
<SupervisorAccountIcon />
</ListItemIcon>
<ListItemText primary="Administrators" />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary="View" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Add administrator" />
</ListItem>
</List>
</Collapse>
<ListItem button onClick={handleClick}>
<ListItemIcon>
<AccessibilityNewIcon />
</ListItemIcon>
<ListItemText primary="Trainers" />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary="View" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Add trainer" />
</ListItem>
</List>
</Collapse>
</List>
</div>
</Drawer>
);
}
Any idea how to do this?
回答1:
You can use a render prop. Here's a CodeSandbox.
回答2:
Use something like that. This is not the best solution. But it will work. You can also use ref.
handleClick = (id) => {
setOpen(id);
}
<ListItem button onClick={() => handleClick('item1')}>
<ListItemIcon>
<AccessibilityNewIcon />
</ListItemIcon>
<ListItemText primary="Trainers" />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open === 'item1'} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary="View" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Add trainer" />
</ListItem>
</List>
</Collapse>
回答3:
We can achieve it by setting id to the list item and retrieving it while the handleClick method is called. Instead of setting an id, the item name can also be passed directly to the handleClick method as answered above.
Link: CodeSandBox
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Collapse from "@material-ui/core/Collapse";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import HomeIcon from "@material-ui/icons/Home";
import SupervisorAccountIcon from "@material-ui/icons/SupervisorAccount";
import AccessibilityNewIcon from "@material-ui/icons/AccessibilityNew";
import VisibilityIcon from "@material-ui/icons/Visibility";
import AddIcon from "@material-ui/icons/Add";
const drawerWidth = 260;
const useStyles = makeStyles(theme => ({
drawer: {
width: drawerWidth,
flexShrink: 0
},
drawerPaper: {
width: drawerWidth
},
drawerContainer: {
overflow: "auto"
},
root: {
width: "100%",
maxWidth: 360,
backgroundColor: theme.palette.background.paper
},
nested: {
paddingLeft: theme.spacing(4)
}
}));
export default function SideBar() {
const classes = useStyles();
const [openedItemId, setOpenedItemId] = React.useState(true);
const handleClick = orgEvent => {
let clickedItemId = orgEvent.currentTarget.id;
if (openedItemId === clickedItemId) {
setOpenedItemId("");
} else {
setOpenedItemId(clickedItemId);
}
//setOpen(!open);
};
return (
<Drawer
className={classes.drawer}
variant="permanent"
classes={{
paper: classes.drawerPaper
}}
>
<Toolbar />
<div className={classes.drawerContainer}>
<List
component="nav"
aria-labelledby="nested-list-subheader"
className={classes.root}
>
<ListItem button>
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText primary="Home" />
</ListItem>
<ListItem id="item-administrators" button onClick={handleClick}>
<ListItemIcon>
<SupervisorAccountIcon />
</ListItemIcon>
<ListItemText primary="Administrators" />
{openedItemId === "item-administrators" ? (
<ExpandLess />
) : (
<ExpandMore />
)}
</ListItem>
<Collapse
in={openedItemId === "item-administrators"}
timeout="auto"
unmountOnExit
>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary="View" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Add administrator" />
</ListItem>
</List>
</Collapse>
<ListItem id="item-trainers" button onClick={handleClick}>
<ListItemIcon>
<AccessibilityNewIcon />
</ListItemIcon>
<ListItemText primary="Trainers" />
{openedItemId === "item-trainers" ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse
in={openedItemId === "item-trainers"}
timeout="auto"
unmountOnExit
>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary="View" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Add trainer" />
</ListItem>
</List>
</Collapse>
</List>
</div>
</Drawer>
);
}
来源:https://stackoverflow.com/questions/63029067/how-to-expand-more-less-only-one-listitem-using-single-method-in-react