Search code examples
reactjsnested-listsexpand

ReactJS Nested List Issue


My nested list in ReactJS opens all sublists when I expand one category

Collapsed List Expand List

import * as React from 'react';
import ListSubheader from '@mui/material/ListSubheader';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Collapse from '@mui/material/Collapse';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';


export default function SideBar() {
    const [open, setOpen] = React.useState(false);
  
    const handleClick = () => {
      setOpen(!open);
    };
  
    return (
      <List
        sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
        component="nav"
        aria-labelledby="nested-list-subheader"
        subheader={
          <ListSubheader component="div" id="nested-list-subheader">
            courses
          </ListSubheader>
        }
      >
        <ListItemButton  onClick={() => handleClick()}>
          <ListItemText primary="Course 1" />
          {open ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={open} timeout="auto" unmountOnExit>
          <List component="div" disablePadding>
            <ListItemButton sx={{ pl: 4 }}>
              <ListItemText primary="Research Paper" />
            </ListItemButton>
          </List>
        </Collapse>

        <ListItemButton>
          <ListItemText primary="Course 2" />
          {open ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>

        <ListItemButton  onClick={() => handleClick()}>
          <ListItemText primary="Course 3" />
          {open  ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={open} timeout="auto" unmountOnExit>
          <List component="div" disablePadding>
            <ListItemButton sx={{ pl: 4 }}>
              <ListItemText primary="Exams" />
            </ListItemButton>
          </List>
        </Collapse>

      </List>
    );
  }

I found the problem might be that I am using an binary operator to open all the lists. I found this solution ReactJs nested list collapse for only one list item but was unable to implement it properly. Any ideas on what I could do?


Solution

  • The issue is all the list components share a single state. Make ListItemButton and Collapse a single component called MyCollapseComponent which holds toggle logic:

    const MyCollapsibleComponent = ({ course, content }) => {
      const [open, setOpen] = React.useState(false);
    
      const handleClick = () => {
        setOpen(!open);
      };
    
      return (
        <>
          <ListItemButton onClick={() => handleClick()}>
            <ListItemText primary={course} />
            {open ? <ExpandLess /> : <ExpandMore />}
          </ListItemButton>
          <Collapse in={open} timeout="auto" unmountOnExit>
            <List component="div" disablePadding>
              <ListItemButton sx={{ pl: 4 }}>
                <ListItemText primary={content} />
              </ListItemButton>
            </List>
          </Collapse>
        </>
      );
    };
    

    Then create individual MyCollapsibleComponent providing the props you want:

    export default function SideBar() {
      return (
        <List
          sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}
          component="nav"
          aria-labelledby="nested-list-subheader"
          subheader={
            <ListSubheader component="div" id="nested-list-subheader">
              courses
            </ListSubheader>
          }
        >
          <MyCollapsibleComponent course="Course 1" content="Research Paper" />
          <MyCollapsibleComponent course="Course 2" content="" />
          <MyCollapsibleComponent course="Course 3" content="Exams" />
        </List>
      );
    }
    

    Code Sandbox Demo

    Edit morning-glade-dxwx5k