1

I am making sidebar menu from .json. Menu items are BMW models. example data bellow

My return:

<List>
      {Menuhandler( menuDataHandler(JsonSeries) )}
</List>

MenuDataHandler makes json to this format

    let seriesData =  {
                "name": 1-series,
                "url" : /1-series,
                "children" : [ 
                    {
                    "name": e82,
                    "url" : /1-series/e82,
                     {
                    "name": e87,
                    "url" : /1-series/e87
                    }
                    }
                  ]}, {
                "name": 2-series,
                "url" : /2-series,
                "children" : [ 
                    {
                    "name": e82,
                    "url" : /2-series/e82
                    },{
                    "name": e87,
                    "url" : /2-series/e87
                    }
                  ]},
                {
                "name": 3-series,
                "url" : /3-series,
                "children" : [ 
                    {
                    "name": e82,
                    "url" : /3-series/e82
                    }, {
                    "name": e87,
                    "url" : /3-series/e87
                    }
                  ]},
                    {
                "name": 4-series,
                "url" : /4-series,
                "children" : [ 
                    {
                    "name": e82,
                    "url" : /4-series/e82
                    },
                   {
                    "name": e87,
                    "url" : /4-series/e87
                    }
                  ]}

Menuhandler is build like this.

const Menuhandler = ( menulist ) => { 

return menulist.map( ( oneMenuItem, i ) => {

  //console.log( oneMenuItem.index)
    /* 
    If oneMenuitem does not have children return listitem to go wanted url. 
    */
      if (!oneMenuItem.children) {
        return (
          <div key={i}>
         <ThemeProvider theme={theme}>
    
            <ListItem button>
              <Link to={ oneMenuItem.url } className="dropdown-link">
                <ListItemText inset primary={ oneMenuItem.name }/>
              </Link>
            </ListItem>
          </ThemeProvider>
          </div>
        )
      }
      /*
      If oneMenuItem have children. Return Listitem and Collapse. Inside 
     Collapse call {Menuhandler(oneMenuItem.children)} so inside Collapse 
     will be children. This is Loop will go until there is no childrens and 
     it will return above ListItem
      */

      return (
        <div key={i}>
        <ThemeProvider theme={theme}>
          <div className="dropdownItem">
            <ListItem
              button
              key={oneMenuItem.index}
              onClick={() => handleClick(oneMenuItem.url)}
            >
              <Link to={oneMenuItem.url} className="dropdown-link">
                <ListItemText inset primary={oneMenuItem.name} />
              </Link>
              
              { open[ oneMenuItem.url ] ? 
                    <ExpandLess /> :
                    <ExpandMore />
                  } 
              
            </ListItem>
            <div className="menubar-handler">
            </div>

            <Collapse
              in={open[oneMenuItem.url]}
              unmountOnExit
              className="childrenItem"
            >
              {Menuhandler(oneMenuItem.children)}
            </Collapse>
          </div>
        </ThemeProvider>
        </div>
      );
    });
  };

HandleClick

const handleClick = ( ComingUrl ) => {
  //console.log(ComingUrl)
  setOpen( prevState => ( {...open, [ ComingUrl ]: !prevState[ ComingUrl ] } ) )
}

Now there comes the fun part. Collapse works now in one state. open[oneMenuItem.url]. HandleClick will make only one object open. In there it will add item : value.

*click* {/1-series:true}.
*next click* {/1-series:true, /2-series: true}. 

Now two collapses are open. If i click the same item again it will make value false and vice versa. Then one collapse closes.

I want to make HandleClick that will automatically closes in samelevel items.

So if open has:

{/1-series:true, /2-series: true, /3-series: true,/4-series: true}

This could not happen. How i want it to be.

 // one scenario
{/1-series:true, /2-series: false, /3-series: false,/4-series: false}
// Second one 
{/1-series:false, /2-series: true, /3-series: false,/4-series: false}

Same would be in children level. If /1-series/e82 is true /1-series/e87 will be false.

1 Answer 1

1

If I understand your question correctly, you have a list with items that can be clicked. Clicking an item expands it to show more data. Only one item can be expanded at one time. Assuming that's correct, here's one approach:

If only one item can be open at a time, why not model your component state so that you just specify which item is open? That way, you only need to keep track of a single value for your state.

Here's a codesandbox of the example below.

function MenuItem({ open, name, onClick, children }) {
  return <li onClick={() => onClick(name)}>{open ? children : name}</li>;
}

function Menu() {
  const [openItem, setOpenItem] = React.useState(null);
  return (
    <ul>
      <MenuItem open={openItem === "foo"} onClick={setOpenItem} name="foo">
        open foo
      </MenuItem>
      <MenuItem open={openItem === "bar"} onClick={setOpenItem} name="bar">
        open bar
      </MenuItem>
      <MenuItem open={openItem === "baz"} onClick={setOpenItem} name="baz">
        open baz
      </MenuItem>
    </ul>
  );
}
Sign up to request clarification or add additional context in comments.

1 Comment

Hey! Thank you for you comment! That is actually very good idea! I am pretty newbie in coding. I have looked many other nested menus and none of them serves my needs. I think we should make one that anybody could use.

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.