How to prevent same component from re-rendering when navigating? React Router v6
I'm new to react and I'm having trouble preventing the components from re-rendering when I navigate to a different page. Im trying to navigate to my Signup and login page which have nothing but a line of text which is the ONLY thing I want displayed.
The problem is that the Navbar re-renders each time I navigate through the links. I tried different times for react-router v6 but the Navbar is always re-rendering below when I navigate. I simply want the text shown only on the screen but the navbar still shows up
I did not include the Navbar as a Route in my code, but it is being shown every time I navigate to a different link as well as my image slider with react bootstrap carousel.
App.js
import React from 'react';
import Navbar from './Components/Navbar/Navbar';
import ImageSlider from './Components/Slideshow/ImageSlider';
import {BrowserRouter as Router, Route, Routes, Switch} from 'react-router-dom';
import Signup from './Components/Navbar/Signup';
import Login from './Components/Navbar/Login';
import './App.css';
function App() {
return (
<div className="App">
<Router>
<Navbar></Navbar>
<Routes>
<Route path='/Signup' element={<Signup />}></Route>
<Route path='/Login' element={<Login />}></Route>
</Routes>
</Router>
<ImageSlider></ImageSlider>
</div>
);
}
export default App;
Navbar.js
import React from 'react';
import { MenuItems } from "./MenuItems";
import {Link,NavLink} from "react-router-dom";
class Navbar extends React.Component {
render() {
return(
<nav className="NavbarItems">
<ul className={this.state.clicked ? 'nav-menu active' : 'nav-menu'}>
{MenuItems.map((item,index) => {
return (
<li key={index}>
<NavLink to={item.url} activeClassName="is-active" className={item.cName} style={{position: 'relative', right: 0, top: 13}}>
{item.title}
</NavLink>
</li>
)
})}
</ul>
</nav>
)
}
}
export default Navbar
MenuItems.js
export const MenuItems = [
{
title: 'Home',
url: '/',
cName: 'nav-links'
},
{
title: 'Sign Up',
url: '/Signup',
cName: 'nav-links'
},
{
title: 'Login',
url: '/Login',
cName: 'nav-links'
}
]
ImageSlider.js
import React from 'react';
import "bootstrap/dist/css/bootstrap.css";
import Carousel from 'react-bootstrap/Carousel';
export default function ImageSlider() {
return (
<div className='slideshow' style={{ height:120}}>
<Carousel controls={false}>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://cdn.suwalls.com/wallpapers/nature/beautiful-sunset-in-grand-canyon-47489-1920x1080.jpg"
alt="Image One"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://wallpaperaccess.com/full/284466.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://i.pinimg.com/originals/09/6a/35/096a35453660aa9b83ba4ab6d9182d61.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://www.teahub.io/photos/full/2-29537_hd-nature-wallpapers-landscape-green-cute-desktop-waterfall.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://wallpaperaccess.com/full/825200.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://wallpaperaccess.com/full/825194.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://hikinglovers.files.wordpress.com/2014/02/high-mountain-hiking-trail-1920x1080-wallpaper-jjr5fr.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://wallpaperaccess.com/full/1859582.jpg"
alt="Image Two"
/>
</Carousel.Item>
<Carousel.Item interval={1500}>
<img
className="d-block w-100"
src="https://cdn.suwalls.com/wallpapers/nature/mountain-shadowing-upon-the-lake-54621-1920x1200.jpg"
alt="Image Two"
/>
</Carousel.Item>
</Carousel>
</div>
);
}
Starting react-router-dom v6, you can split your components and have them rendered only on speicifc routes.
Your App.js
should be like
<Router>
<Routes>
<Route element={
<>
<Navbar />
<Outlet />
<ImageSlider />
</>
}>
// routes for authenticated users where navbar & image slider should be displayed
<Route path='/home' element={<Home />}> </Route>
</Route>
<Route element={<Outlet />}>
// routes where navbar & image slider is not rendered
<Route path='/Signup' element={<Signup />}> </Route>
<Route path='/Login' element={<Login />}> </Route>
</Route>
</Routes>
</Router>
By doing this, your /home
route will always have Navbar
& ImageSlider
component, where as the guest routes will have only the element that is passed as prop to the route.
As your app grows, I'd suggest to split this into Layouts
folder to contain
- Auth Layout - a component that renders all common components for authenticated users
- Guest Layout - a component that renders all common components for guest users
so that you can leverage from async code like useEffect
or any other hook.
I've drafted a demo to showcase how you can use achieve this by splitting into seperate components.
https://codesandbox.io/s/multiple-layouts-react-7r8qu