The thing I'm trying is a multipage react app where I can navigate between pages(like from the main route '/' to '/whitepape' or 'privacyPolicy'), but I have 4 different routes('/', 'services', 'features', 'contactUs') within the main route '/' which use react-scroll to get the scrolling between those 4 components whose links are added in the Navbar(this part works as expected).
But navigating between pages like replacing entirely all 4 components with whitepaper page or privacyPolicy page, with Navbar and Footer at the same place so that I can navigate back to home.
This is what I’m stuck at any help is appreciated I’m not sure I’m following the right way to implement what I need. I have been using React Navigation in react native which is simple to understand and straightforward, wish react-router was so straight forward instead react-router is a bit confusing.
App.js
function App() {
return (
<div className="App">
<Navbar />
<Switch>
<Route path="/">
<>
<Hero />
<Services />
<Features />
<ContactUs />
</>
</Route>
<Route path="/whitepaper">
<WhitePaper />
</Route>
</Switch>
<Footer />
</div>
)
}
Navbar.js
import { Link } from 'react-scroll'
import { withRouter, Link as RouterLink } from 'react-router-dom'
const menuItems = [
{
menuTitle: 'Home',
pageURL: '/',
id: 'hero'
},
{
menuTitle: 'Services',
pageURL: '/services',
id: 'services'
},
{
menuTitle: 'Features',
pageURL: '/features',
id: 'features'
},
{
menuTitle: 'Contact Us',
pageURL: '/contactUs',
id: 'contactUs'
}
]
const Navbar = ({ history }) => {
const classes = useStyles()
const [anchorEl, setAnchorEl] = useState(null)
const [showNav, setShowNav] = useState(false)
const open = Boolean(anchorEl)
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
const [isActive, setIsActive] = useState('/')
useEffect(() => {
setIsActive(history.location.pathname)
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
setShowNav(true)
} else {
setShowNav(false)
}
})
return () => {
window.removeEventListener('scroll', () => setShowNav(false))
}
})
const handleMenu = event => {
setAnchorEl(event.currentTarget)
}
const handleMenuClick = pageURL => {
history.push(pageURL)
setAnchorEl(null)
}
const handleClose = () => {
setAnchorEl(null)
}
const handleLinkClick = pageURL => {
history.push(pageURL)
}
return (
<div>
<AppBar
position="static"
elevation={0}
className={`${classes.appBar} ${
showNav ? classes.appBarOnScroll : classes.appBar
}`}>
<Container>
<Toolbar className={classes.toolbar}>
<Link to="hero" smooth duration={1000}>
<RouterLink to="/">
<img src={logo} alt="Company Logo" className={classes.logo} />
</RouterLink>
</Link>
{isMobile ? (
<div>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
onClick={handleMenu}
aria-label="menu">
<MenuIcon />
</IconButton>
<Menu
className={classes.mobileMenu}
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right'
}}
open={open}
onClose={handleClose}>
{menuItems.map(menuItem => {
const { menuTitle, pageURL, id } = menuItem
return (
<Link key={menuTitle} to={id} smooth duration={1000}>
<MenuItem
className={
isActive === pageURL
? classes.mobileActiveMenuItem
: classes.mobileMenuItem
}
onClick={() => handleMenuClick(pageURL)}>
{menuTitle}
</MenuItem>
</Link>
)
})}
</Menu>
</div>
) : (
<div className={classes.menu}>
<Link
to="home"
smooth
duration={1000}
className={
isActive === '/' ? classes.menuActiveLink : classes.menuLink
}
variant="contained"
onClick={() => handleLinkClick('/')}>
Home
</Link>
<Link
to="services"
smooth
duration={1000}
className={
isActive === '/services'
? classes.menuActiveLink
: classes.menuLink
}
variant="contained"
onClick={() => handleLinkClick('/services')}>
Services
</Link>
<Link
to="features"
smooth
duration={1000}
className={
isActive === '/features'
? classes.menuActiveLink
: classes.menuLink
}
variant="contained"
onClick={() => handleLinkClick('/features')}>
Features
</Link>
<Link
to="contactUs"
smooth
duration={1000}
className={
isActive === '/contactUs'
? classes.menuActiveLink
: classes.menuLink
}
variant="contained"
onClick={() => handleLinkClick('/contactUs')}>
ContactUs
</Link>
</div>
)}
</Toolbar>
</Container>
</AppBar>
</div>
)
}
export default withRouter(Navbar)
Footer.js
import { Link } from 'react-scroll'
import { Link as RouterLink } from 'react-router-dom'
const Footer = () => {
const classes = useStyles()
const icons = [
{
img: linkedin,
alt: 'linkedin',
url: 'https://www.linkedin.com/company/company'
},
{
img: twitter,
alt: 'twitter',
url: 'https://twitter.com/company'
},
{
img: instagram,
alt: 'instagram',
url: 'https://www.instagram.com/company/'
},
{
img: facebook,
alt: 'facebook',
url: 'https://www.facebook.com/company/'
}
]
return (
<div className={classes.footer}>
<Container className={classes.container}>
<Grid container spacing={4}>
<Grid item md={3} xs={12}>
<div className={classes.column}>
<Link to="hero" smooth duration={1000}>
<RouterLink to="/">
<img className={classes.logo} src={logo} alt="Company Logo" />
</RouterLink>
</Link>
</div>
</Grid>
<Grid item md={3} xs={12}>
<div className={classes.column}>
<div>
<Grid item>
<span className={classes.linksTitle}>USEFUL LINKS</span>
</Grid>
<Grid item className={classes.links}>
<RouterLink to="/whitepaper" replace className={classes.link}>
<span className={classes.span}>White Paper</span>
</RouterLink>
</Grid>
<Grid item className={classes.links}>
<a
href="mailto:xyz@comapmy.com"
className={classes.link}>
<span className={classes.span}>Email Our CEO</span>
</a>
</Grid>
<Grid item className={classes.links}>
<RouterLink to="/" className={classes.link}>
<span className={classes.span}>Privacy Policy</span>
</RouterLink>
</Grid>
</div>
</div>
</Grid>
<Grid item md={3} xs={12}>
<div className={classes.column}>
{icons.map(icon => {
return (
<a href={icon.url} key={icon.alt}>
<img
className={classes.icon}
src={icon.img}
alt={icon.alt}
/>
</a>
)
})}
</div>
</Grid>
<Grid item md={3} xs={12}>
<div className={classes.top}>
<Link to="hero" smooth duration={1000}>
<RouterLink to="/">
<div>
<img src={top} alt="back to top" />
<p>Back To Top</p>
</div>
</RouterLink>
</Link>
</div>
</Grid>
</Grid>
<Grid container>
<Grid item xs={12}>
<div className={classes.footerBottom}>
<p className={classes.copyright}>
© 2021 Copyrights •{' '}
<Link to="hero" smooth duration={1000}>
<RouterLink to="/" className={classes.company}>
<span>company.com</span>
</RouterLink>
</Link>
</p>
</div>
</Grid>
</Grid>
</Container>
</div>
)
}
export default Footer
Within the Switch
component path order and specificity matter. This isn't a detail that is overtly called out in their docs though. You want to order your more specific paths before less specific paths. Think of path
as more of a prefix, and you'll see that "/" is a path prefix for all paths.
The Switch
returns and renders the first matching path it finds in its children.
Just invert the order of your paths such that "/whitepaper"
is listed prior to the more general/less specific "/"
path.
function App() {
return (
<div className="App">
<Navbar />
<Switch>
<Route path="/whitepaper">
<WhitePaper />
</Route>
<Route path="/">
<>
<Hero />
<Services />
<Features />
<ContactUs />
</>
</Route>
</Switch>
<Footer />
</div>
)
}