1

I'm trying to create a dynamic menu using React and I'm struggling to implement the collapse functionality. I start by mapping each MenuItem using a Json object which works fine. Afterwards, when I tried to implement a collapse functionality when clicked on, all the menuitems collapse instead of just the one that is clicked on. I tried implementing an array which toggles between true/false but I'm having trouble accessing the value when clicked upon. Here is the code:

import React, { Component } from "react";
import styled from "styled-components";
import "./sidebar.css";
import Collapse from 'react-bootstrap/Collapse'
const dashboardItems = [
    {
        id: 1,
        title: "Dashboard",
        subtitles: ["Analysis", "Monitor", "Workpplace"],
        text: "Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 2,
        title: "Form",
        subtitles: ["Basic Form", "Step Form", "Advanced Form"],
        text: "enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."

    },
    {
        id: 3,
        title: "List",
        subtitles: ["Search Table", "Basic List", "Card List"],
        text: "richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 4,
        title: "Profile",
        subtitles: ["Basic Profile", "Advanced Profile"],
        text: "Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 5,
        title: "Result",
        subtitles: ["Success", "Failure"],
        text: "craft beer labore wes anderson cred nesciunt sapiente ea proident."
    },
    {
        id: 6,
        title: "Account",
        subtitles: ["Account Center", "Account Settings"],
        text: "wes anderson cred nesciunt sapiente ea proident."
    }
];


function Sidebar(){
        const [open, setOpen] = React.useState(false);
        const [clickedItems, setClickedItems] = React.useState( [false, false, false, false, false, false] );
        function handleClick(id) {
            console.log("initial value at " + id + " is " + clickedItems[id - 1] + " array is " + clickedItems)
            clickedItems[id - 1] = !clickedItems[id - 1];
            console.log(clickedItems);
            setOpen(!open)
        }

        return (
           <SidebarContainer>
               <SidebarMenu>
                   <MenuLogo>
                   Dashboard
                   </MenuLogo>                

                    {dashboardItems.map((postData) => {
                        return(
                            <div key = {postData.id} >
                                <SidebarMenuItem 
                                    onClick={() => handleClick(postData.id)}
                                >
                                        <SidebarMenuItemLabel>{postData.title}</SidebarMenuItemLabel>
                                </SidebarMenuItem>
                                <Collapse in={open}>
a                                    <div key={postData.id} id="example-collapse-text" className="collapsedText">
                                        {postData.text}
                                    </div>
                                </Collapse>
                           </div>
                        );
                    })}
                </SidebarMenu>
            </SidebarContainer>
        );
}


const SidebarContainer = styled.div`
        height: 100vh;
        width: 270px;
        background-color: #252529;
        color: #fff;
        display: flex;
        flex-direction: column;
        font-family: "Roboto", sans-serif;
`;

const SidebarMenu = styled.ul`
        display: flex;
        align-items: left;
        flex-direction: column;
        list-style: none;
        width: 100%;
        padding-left: 0px;
`;

const MenuLogo = styled.div`
        display: flex;
        align-items: center;
        justify-content: start;
        gap: 16px;
        font-size: 18px;
        line-height: 1.5;
        font-weight: 600;
        height: 45px;
        color: #fff;
        margin: 30px 30px 30px 30px;
        padding-bottom: 20px;
        border-bottom: 1px solid #2e2e33;
`;

const SidebarMenuItem = styled.li`
        display: flex;
        height: 40px;
        width: 100%;
        align-items: center;
        padding-left: 30px;
        &:hover {
        background: rgba(255, 255, 255, 0.05);
        box-shadow: inset 3px 0 0 0 #ffffff;
        cursor: pointer;
}
`;

const SidebarMenuItemLabel = styled.p`
        font-family: "Open Sans", sans-serif;
        color: #fff;
        font-size: 16px;
        font-weight: 600;
        line-height: 1.3;
        text-align: left;
        padding: 15px 0px;
        margin-left: 15px;
        margin-top: 15px;
        color: #ffffff;
`;


export default Sidebar;

Please let me know if you might know of a solution. Thanks!

2
  • Can you please show the collapse function code. Commented Jun 18, 2020 at 16:22
  • The collapse function is implemented through the react-bootstrap api. Commented Jun 18, 2020 at 17:19

2 Answers 2

2
import React, { useState } from "react";

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";

const getCustomOptions = () => {
  const items = [
    {
      id: 1,
      title: "Some Chart option 1",
      subMenu: "some subMenu 1",
    },
    {
      id: 2,
      title: "Some Chart option 2",
      subMenu: "some subMenu 2",
    },
    {
      id: 3,
      title: "Some Chart option 3",
      subMenu: "some subMenu 3",
    },
    {
      id: 4,
      title: "Some Chart option 4",
      subMenu: "some subMenu 4",
    },
  ];
  return items;
};

function CustomNestedList() {
  const [open, setOpen] = useState({});

  const items = getCustomOptions();

  const handleClick = (id) => {
    setOpen((prevState) => ({ ...prevState, [id]: !prevState[id] }));
  };

  return (
    <List>
      {items.map((item) => {
        return (
          <>
            <ListItemButton onClick={() => handleClick(item.id)}>
              <ListItemText primary={item.title} />
              {open[item.id] ? <ExpandLess /> : <ExpandMore />}
            </ListItemButton>
            <Collapse in={open[item.id]} timeout="auto" unmountOnExit>
              <List component="div" disablePadding>
                <ListItemButton className="pl-4">
                  <ListItemText primary={item.subMenu} />
                </ListItemButton>
              </List>
            </Collapse>
          </>
        );
      })}
    </List>
  );
}

export default CustomNestedList;

Sign up to request clarification or add additional context in comments.

Comments

1

Your "open" variable should be an empty object.


const [open, setOpen] = React.useState({});

Then on the handleClick function you create a new field that has "id" as key.

function handleClick(id) {
            setOpen((prevState => ({...prevState, [id]: !prevState[id]}))
        }

Then use that as the "open" prop.


 <Collapse in={open[postData.id]}>
  <div key={postData.id} id="example-collapse-text" className="collapsedText">
    {postData.text}
  </div>
 </Collapse>

Keep in mind that when you want to access the actual state, you always want to do this:

const [state, setState] = useState(true)
setState(prevState => !prevState)

And never

const [state, setState] = useState(true)
setState(!state) // <-- THIS IS BAD

3 Comments

Hi Lenni, thanks for the help! When I try to implement the following: setOpen(prevState => ({...prevState, [id]: !prevState[id]})), I get an error saying TypeError: Cannot read property 'className' of undefined. Do I need to pass in additional information?
It would be helpful if you share more info about the error :)
Sorry, I think I did something wrong previously. This is now working as intended. Thanks so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.