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.