Reputation: 121
Im trying to use material Ui with my react frontend project. I have implemented the AppBar and drawer component and they are working just fine. This is what I have achieved till now :
export default function MiniDrawer() {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<CssBaseline />
<AppBar style={{background: 'black'}}
position="fixed"
className={clsx(classes.appBar, {
[classes.appBarShift]: open,
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, {
[classes.hide]: open,
})}
>
<MenuIcon />
</IconButton>
<Typography className={classes.mystyle} variant="h5" >
CodeBasics
</Typography>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
}),
}}
open={open}
>
<div className={classes.toolbar}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'rtl' ? <ChevronRightIcon /> : <ChevronLeftIcon />}
</IconButton>
</div>
<Divider />
<List>
{['Home', 'Algorithms', 'DataStructures'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<Layout>
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/DataStructures" component={DataStructures} />
</Switch>
</Router>
</Layout>
</main>
</div>
);
}
Now I want to map each 'Home', 'DataStructures' and 'Algorithms' with a different route. I have achieved a way to a route the List component in this way.
<List>
{['Home', 'Algorithms', 'DataStructures'].map((text, index) => (
<ListItem button key={text} component="a" href="www.google.com">
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
but with its only getting me go to the same link for every item in the list. How do I map individual list items with individual routes?
Upvotes: 2
Views: 2965
Reputation: 1189
I've put together a small sample. This structure works for me for all of my projects and quite fast to implement once you've got the hang of it.
Route Structure
This pathIds
variable is an object which holds all id values for routes. This will be useful when needing a reference to auto generate breadcrumb links.
const pathIds = {
home: 'home',
...
}
This pathRouting
variable is an object which holds all path routing. Just path routing.
const pathRouting = {
home: '/home',
...
}
Primary structure object:
const pageRoutes = {
[pathIds.home]: {
path: pathRouting.home,
sidebarName: 'Homepage',
icon: Dashboard,
noRender: false,
component: Home,
},
...
}
This is primary structure object, holding all necessary info to generate onto HTML (sidebar, breadcrumbs, routes etc).
pathRouting
object. (Required)Then, in your app.js
, you import pageRoutes
as usual. Before doing mapping or iteration work, you might need to convert this object to an array (or use a library like lodash
to directly iterating on the object).
const routeArray = Object.values(pageRoutes);
Then:
<Switch>
{routeArray.map((prop, key) => {
return (
<Route
path={prop.path}
component={prop.component}
exact={prop.exact || false}
key={`route-${key}`}
/>
);
})}
<Route component={pageRoutes[pathIds.error404].component} />
</Switch>
Notice the very last line where I explicitly declare a fallback <Route />
path in case user is on a wrong/ not defined path, that's how useful an object is in this kind of situation. It doesn't need path
prop.
You sidebar is just a simple component receives a list of routes as props (as converted in app.js
), then it can be used to show on the view.
<List component="nav" aria-label="main mailbox folders">
{routes.map(({ path, noRender, sidebarName, ...prop }, index) => {
if (noRender) return null;
return (
<NavLink to={path} key={`route-${index}}`}>
<ListItem button>
<ListItemIcon>
<prop.icon />
</ListItemIcon>
<ListItemText primary={sidebarName} />
</ListItem>
</NavLink>
);
})}
</List>
You will see it only renders Homepage, Inbox and Reset Password
on sidebar. But you can directly enter /register
to make <Register />
show up. The same for /page-not-found
. Or even when you enter a wrong address like /register-user
, the <PageNotFound />
component will be used for fallback case.
You might wonder why I don't put all path routes and path Ids in its own place, why do I need to move them into a separate object? The answer is, in my case I usually need quick access to those values. This might be useful for generating breadcrumbs or do some iteration without pulling the whole object. Depend on your specific project needs, those two might be shortened.
For full code, you can visit here: Sample Link
Upvotes: 1
Reputation: 121
I have found a way to achieve this. First I created an array of objects like:
const topics= [{
topic: "Home",
path: "home"
},
{
topic: "DataStructures",
path: "datastructures"
}]
then I did this:
<List>
{topics.map((text, index) => (
<ListItem button key={text.topic} component="a" href={text.path === "home"? "\\":text.path}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text.topic} />
</ListItem>
))}
</List>
Upvotes: 0