buzz
buzz

Reputation: 1106

Creating a Mega menu in react with loop

I have created a mega menu where the values will be dynamic (coming from the API). So you never know how many links will be there. But for testing purpose I've put 50 texts in array menu and trying to loop over that so that it look Like this . So there's a parent row and inside that there are 5 columns, each containing 5 links. Per row will contain 5 columns or 25 links.

JSX

const menu = [
  "one",
  "two",
  "three",
  "four",
  "five",
  "one",
  "two",
  "three",
  "four",
  "five",
 ... (total 50)
];

           <Box className={classes.rows}>
              <Box className={classes.cols}>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
              </Box>
              <Box className={classes.cols}>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
              </Box>
              <Box className={classes.cols}>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
              </Box>
              <Box className={classes.cols}>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
              </Box>
              <Box className={classes.cols}>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
                <Typography variant="body1" className={classes.link}>
                  Link 1
                </Typography>
              </Box>
            </Box>

I tried using for loop and then create another 2D array. And later planned to map through that array inside JSX.

 let links = [];

  if (menu.length != 0) {
    for (let i = 0; i < menu.length; i++) {
      for (let j = 0; j < 5; j++) {
        links.push(menu[i]);
      }
    }
  }

But it won't work I know. Can anyone help me with this?

Upvotes: 0

Views: 465

Answers (2)

coot3
coot3

Reputation: 632

First you have to divide your links up into groups of 5. Each group of 5 links will be put in a box with a defined width of 20% (or just under to allow for padding/margins, this will give 5 columns per page).

Then use flexbox with flexwrap: 'wrap' to handle your dynamic links and map your group boxes into that.

Here is an example:

https://codesandbox.io/s/youthful-chaum-83m4vl?file=/src/App.js

import { Box, Typography } from "@mui/material";
import "./styles.css";

const links = [...];

export default function App() {
  // how many groups of 5 given the length of the links array
  const numberOfGroups =
    Math.floor(links.length / 5) + (links.length % 5 > 0 ? 1 : 0);

  const linkGroups = [];

  for (let index = 0; index < numberOfGroups; index++) {
    // push each group of 5 into the linkGroups array
    linkGroups.push(links.slice(index * 5, (index + 1) * 5));
  }

  return (
    <div className="App">
      <Box
        sx={{
          display: "flex",
          width: "100vw",
          flexWrap: "wrap",
          backgroundColor: "lightgrey"
        }}
      >
        {linkGroups.map((linkGroup) => (
          <Box
            sx={{
              width: "18%",
              mb: "16px",
              borderRight: "1px solid white"
            }}
          >
            {linkGroup.map((link) => {
              return <Typography>{link}</Typography>;
            })}
          </Box>
        ))}
      </Box>
    </div>
  );
}

Upvotes: 1

Macilquham
Macilquham

Reputation: 282

Not sure if this is what you are after but the code below:

function Row() {
  return (
    <div className="row">
      <p>Link</p>
    </div>
  );
}

const Column = ({ numberOfRows }) => {
  const rows = [];
  for (var i = 0; i < numberOfRows; i++) {
    rows.push(<Row key={i} />);
  }

  return (
    <div className="column">
      <div>Column</div>
      <div>{rows}</div>
    </div>
  );
};

function App() {
  const mockedNumberOfReturnedMenuItems = 28
  const menu = Array.from({ length: mockedNumberOfReturnedMenuItems }, (v, i) => i + 1);
  const maxItemsPerRow = 5;
  const totalNumberOfColumnsRequiredRoundedDown = Math.floor(menu.length / maxItemsPerRow);
  const totalNumberOfMenuItemsDividedByMaxItemsHasRemainder = menu.length % maxItemsPerRow;
  const columnCount = totalNumberOfColumnsRequiredRoundedDown + (totalNumberOfMenuItemsDividedByMaxItemsHasRemainder ? 1 : 0);
  const columns = [];

  for (var i = 0; i < columnCount; i++) {
    var rowCount =
      i + 1 != columnCount ? maxItemsPerRow : menu.length % maxItemsPerRow;
    columns.push(<Column key={i} numberOfRows={rowCount} />);
  }

  return <div>{columns}</div>;
}

Produces this

enter image description here

Upvotes: 1

Related Questions