简体   繁体   中英

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

  1. Auth Layout - a component that renders all common components for authenticated users
  2. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM