In the last article, I built a basic Drawer
that, at the end of this article, will contain a full working navigation block.
Installing React Router DOM
At the root folder of football-almanac
, I run
npm install react-router-dom @types/react-router-dom
It'll install React Router DOM.
Designing the navigation
First three URLs that come in mind for an application like this are
-
/
(the home page) /standings
/teams
Implementing React Router DOM
Wrap everything!
To get started, I import BrowserRouter
in index.tsx
and I wrap the whole application within it.
......
import { BrowserRouter } from 'react-router-dom';
......
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
At this point, since the App
component is going to grow too much, I split it into multiple components. This will help me to ensure a good level of isolation of them, also for testing purposes.
The Router
object
I find very helpful defining my routes as an object like this
const Routes = [
{
path: [url],
sidebarName: [label],
icon: [material_ui_icon_name],
component: [component_name],
},
...
];
In this way, I can define my router once and reuse it when I need, as a module.
I define my routes in Routes.tsx
.
import React from 'react';
const Home: React.FC = () => {
return (
<h1>Home</h1>
);
};
const Standings: React.FC = () => {
return (
<h1>Standings</h1>
);
};
const Teams: React.FC = () => {
return (
<h1>Teams</h1>
);
};
const Routes = [
{
path: '/',
sidebarName: 'Home',
component: Home
},
{
path: '/standings',
sidebarName: 'Standings',
component: Standings
},
{
path: '/teams',
sidebarName: 'Teams',
component: Teams
},
];
export default Routes;
For the moment I create some placeholder components (Home
, Standings
and Teams
).
The NavigationBar
I create a new component subfolder, named NavigationBar
. The new component is NavigationBar.tsx
.
import React, { useState } from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import Routes from '../App/Routes';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import {
AppBar,
Toolbar,
Typography,
IconButton,
Drawer,
MenuList,
MenuItem,
ListItemText,
} from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
drawer: {
width: 300,
},
fullList: {
width: 'auto',
},
}),
);
const NavigationBar: React.FC = (props: any) => {
const classes = useStyles();
const [isOpen, setIsOpen] = useState(false);
const toggleDrawer = (open: boolean) => (
event: React.KeyboardEvent | React.MouseEvent,
) => {
if (
event.type === 'keydown' &&
((event as React.KeyboardEvent).key === 'Tab' ||
(event as React.KeyboardEvent).key === 'Shift')
) {
return;
}
setIsOpen(open);
};
const activeRoute = (routeName: any) => {
return props.location.pathname === routeName ? true : false;
}
return (
<div>
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu" onClick={toggleDrawer(true)}>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Football Almanac
</Typography>
</Toolbar>
</AppBar>
</div>
<Drawer classes={{ paper: classes.drawer }} open={isOpen} onClose={toggleDrawer(false)}>
<div
className={classes.fullList}
role="presentation"
onClick={toggleDrawer(false)}
onKeyDown={toggleDrawer(false)}
>
<MenuList>
{Routes.map((prop, key) => {
return (
<NavLink to={prop.path} style={{ textDecoration: 'none' }} key={key}>
<MenuItem selected={activeRoute(prop.path)}>
<ListItemText primary={prop.sidebarName} />
</MenuItem>
</NavLink>
);
})}
</MenuList>
</div>
</Drawer>
</div>
);
};
export default withRouter(NavigationBar);
To have the browser navigation available within this component, I used a higher-order component that comes with React Router DOM, withRouter
.
It passes updated
match
,location
, andhistory
props to the wrapped component whenever it renders.
To learn more about withRender
, take a look at the documentation.
App.tsx
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Routes from './Routes';
import NavigationBar from './NavigationBar/NavigationBar';
const App: React.FC = () => {
return (
<div>
<NavigationBar />
<Switch>
{Routes.map((route: any) => (
<Route exact path={route.path} key={route.path}>
<route.component />
</Route>
))}
</Switch>
</div>
);
}
export default App;
Understanding the following snippet is essential: since we can easily add and remove routes from an independent module, it's enough iterating it and create a Route for each route defined in the object.
<Switch>
{Routes.map((route: any) => (
<Route exact path={route.path} key={route.path}>
<route.component />
</Route>
))}
</Switch>
The result is the following
What's next
In the next step I will create the home page that will display some data fetched from the APIs.
Useful resources
- React Router DOM (Web and Native) https://reacttraining.com/react-router/
-
withRouter
https://reacttraining.com/react-router/web/api/withRouter - Material UI
<MenuList>
https://material-ui.com/api/menu-list/
Top comments (1)
could you please tell.. how to create drawer navigation using javascript syntax in react js.