Prevent React component re render when route change

Viewed 3746

I am using react-router-dom.

let's assume I have 2 pages like Homepage and Profile Page. Both pages have a component named a Header.

In the Header component, using useEffect React Hook I am calling a fetch request on my back-end server and fetching logged-in user data. API returns username, avatar image, etc. (that's not a problem)

thing is that. when I jump from "Homepage" to "profile page", the Header component, re-render and send the request to the server again. this occurs every time when I jump from the homepage to the profile page or profile page to the home page. and the data displayed on the Header keeps loading until the fetched request succeeds.

I want something like Youtube.

Header Component

import {useState , useEffect} from 'react'

import Logo from './imgs/logo.png'
import {Link} from 'react-router-dom'

import { FaArrowRight , FaServicestack , FaFirstOrder} from "react-icons/fa";
import { BsPersonCheck , AiOutlineContacts } from "react-icons/all";


const ShowOrHideNav = ()=>{
    var nav = document.getElementById('NavBarSpingbuck')
    nav.classList.toggle('hidden')
}


const Header = () =>{
    const [loggedIn , setLoggedIn] = useState(false)
    const [user_data , setUserData] = useState(undefined)

    const Logout = () =>{
        localStorage.removeItem('sb_auth_token')
        UpdateHeader()
    }

    const UpdateHeader = () =>{
        const auth_token = localStorage.getItem('sb_auth_token')
        if(auth_token){
            console.log('sending request')
            fetch(
                'https://dummy_API_URL.dummy_domain.com/authentication/user/',
                {
                    headers:{
                        Authorization : 'Token ' + auth_token,
                    },
                }
            )
            .then(response => response.json())
            .then(resp_data =>{
                if(resp_data.status == 200){
                    setUserData(resp_data.data)
                }
            })
            .catch(error =>{
                console.log(error)
                console.log('error')
            })
            setLoggedIn(true)
        }
        else{
            setLoggedIn(false)
        }
    }

    useEffect(()=>{
        UpdateHeader()
        
    } , [])
    return(
        <div className=' fixed top-0 z-50 w-full shadow bg-black bg-opacity-75 px-5' style={{backdropFilter:'blur(18px)'}}>
            <div className='container py-2 flex items-center justify-between mx-auto relative'>
                <div className='w-8 h-8 md:hidden flex flex-col justify-evenly items-end cursor-pointer group ' onClick={ShowOrHideNav}>
                    <span className='w-2 h-1 bg-white block rounded-full transition-all delay-150 duration-300 group-hover:w-8'></span>
                    <span className='w-4 h-1 bg-white block rounded-full transition-all duration-300 group-hover:w-8'></span>
                    <span className='w-8 h-1 bg-white block rounded-full '></span>
                </div>
                <div>
                    <Link to='/'>
                        <img src={Logo} className='w-32 ' />
                    </Link>
                </div>
                <div className='px-5'>
                    <ul className='items-center hidden p-4 md:p-0 md:flex absolute md:relative top-full md:top-0 w-full md:w-auto z-50 left-0 bg-white md:bg-transparent rounded-lg md:rounded-none transition-all duration-300' style={{animationIterationCount:1}} id='NavBarSpingbuck'>
                        <li className='hover:scale-110 duration-150 transform px-4 mb-4 md:mb-0' >
                            <Link className='flex flex-col items-center text-gray-800 md:text-white'>
                                <p>Jobs</p>
                            </Link>
                        </li>
                        <li className='hover:scale-110 duration-150 transform px-4 mb-4 md:mb-0' >
                            <Link className='flex flex-col items-center text-gray-800 md:text-white'>
                                <p>Services</p>
                            </Link>
                        </li>
                        <li className='hover:scale-110 duration-150 transform px-4 mb-4 md:mb-0' >
                            <Link className='flex flex-col items-center text-gray-800 md:text-white'>
                                <p>Place Order</p>
                            </Link>
                        </li>
                        <li className='hover:scale-110 duration-150 transform px-4 mb-4 md:mb-0' >
                            <Link className='flex flex-col items-center text-gray-800 md:text-white'>
                                <p>About</p>
                            </Link>
                        </li>
                        <li className='hover:scale-110 duration-150 transform px-4 mb-4 md:mb-0' >
                            <Link className='flex flex-col items-center text-gray-800 md:text-white'>
                                <p>Contact</p>
                            </Link>
                        </li>
                    </ul>
                </div>
                <div className='account_bar'>
                    {
                        loggedIn?
                        <div className='flex items-center cursor-pointer group relative py-1'>
                            <div className='mr-3 rounded-full w-10 h-10 bg-center bg-cover' style={{backgroundImage:'url(https://pixinvent.com/materialize-material-design-admin-template/app-assets/images/user/12.jpg)'}}>
    
                            </div>
                            {
                                user_data && user_data.username ?
                                <p className='text-white'>{user_data.username}</p>: <p className='text-white'>User</p>

                            }
                            <div className='bg-white rounded-md py-2 w-28 absolute top-full shadow-2xl hidden group-hover:block'>
                                <ul>
                                    <li className='px-2 py-1 hover:bg-blue-100'>
                                        <Link className='block' to='/profile/' >Profile</Link>
                                    </li>
                                    <li className='px-2 py-1 hover:bg-blue-100' onClick={()=>{Logout()}}>
                                        Logout
                                    </li>
                                </ul>
                            </div>
                        </div>
                            

                        :
                        <Link to='/authentication/login/' >
                            <div className='bg-yellow-600 py-0.5 px-2 rounded flex items-center justify-center hover:bg-yellow-700 transition-all duration-300'>
                                <p className='text-white pr-1'>Sign in</p>
                                <FaArrowRight className='text-white text-sm' />
                            </div>
                        </Link>
                    }
                </div>
                
            </div>
        </div>
    )
}

export default Header 
2 Answers

Extract the Header component and place it on the same level with the Switch component.

<Router>
  <Header />
  <Switch>
    <Route path="/">
      <Home />
    </Route>
    <Route path="/profile">
      <Profile />
    </Route>
  </Switch>
</Router>

You can render your Header component on its own route, separate from the route rendering either the home or profile pages. Use an array of paths you want the header component's Route to match. Presuming "/" is your homepage then you may also want to specify the exact prop so "/" doesn't match every path you have. This all, of course, also assumes the header component is rendered before all other content on the page for each of the home and profile pages.

Example:

<Router>
  <Route exact path={["/profile", "/"]} component={Header} />
  <Switch>
    <Route path="/profile" component={ProfilePage} />
    <Route path="/" component={HomePage" />
  </Switch>
</Router>
Related