skip to Main Content

I am trying to use useEffect hook of react to render a component(SideNavbar) but the component(SideNavbar) is not changing until i reload the page manually.
The system works when i reload the page but how can i do it without having to manualy reload the page.

I need to remove a Sidenavbar when user is not logged in and display the navbar when user is logged in.
How to make the component rerender as soon as the user has succesfully logged in?
Also How to hide the component (SideNavbar) as soon as the user logs Out.

import Navbar from "./Components/Navbar";
import React, { useEffect, useState } from "react";
import { Route,Routes } from "react-router";
import Home from "./Routes/Home";
import Contact from "./Routes/Contact";
import Enroll from "./Routes/Enroll";
import Login from "./Routes/Login";
import SideNavbar from "./Components/InnerComponents/SideNavbar";
import Profile from './Routes/Admin/Profile';
import Notice from './Routes/Admin/Notice';
import Result from './Routes/Admin/Result';
import StudentList from "./Routes/Admin/StudentList";
import TeacherList from "./Routes/Admin/TeacherList";
import Classroom from "./Routes/Admin/Classroom";
import NoticeState from "./context/notices/NoticeState";
import NewAccount from "./Routes/Admin/NewAccount.js"
import UserState from "./context/user/UserState";


function App() {
  
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(()=>{
    if(localStorage.getItem('token')){
      setIsLoggedIn(true);
    }
  },[localStorage.getItem('token')])
    
  

  return (
    <div className="App">
    <UserState>
      <NoticeState>
        <Navbar/>
        {isLoggedIn && <SideNavbar/>}
        <div className="containerApp">
          <Routes>
            <Route element={<NewAccount/>} exact path='/newaccount' />
            <Route element={<Profile/>} exact path='/profile' />
            <Route element={<Notice/>} exact path="/notice"/>
            <Route element={<Result/>} exact path="/result"/>
            <Route element={<TeacherList/>} exact path="/teacherList" />
            <Route element={<Classroom/>} exact path="/classroom" />
            <Route element={<StudentList/>} path="/classroom/:classID"/>
            

            <Route element={<Home/>} exact path='/' />
            <Route element={<Contact/>} exact path='/contact' />
            <Route element={<Enroll/>}  exact path='/enroll' />
            <Route element={<Login/>}  exact path='/login' />
          </Routes>
        </div>
      </NoticeState>
      </UserState>
    </div>
  );
}

export default App;

2

Answers


  1. The problem is in this useEffect

    useEffect(()=>{
        if(localStorage.getItem('token')){
          setIsLoggedIn(true);
        }
      },[localStorage.getItem('token')])
    

    Because in deps array, there is localStorage.getItem('token'), which is called once, the <App/> has no reason to rerender (which is caused by setState).
    The quickest solution is to create a periodical check if there is a token in the localStorage.

    useEffect(() => {
       const intervalIntance = setInterval(() => {
          if(localStorage.getItem('token')) setIsLoggedIn(true)
          else setIsLoggedIn(false)
       }, 500); // check every 500 ms
    
       // on unmount remove the interval to prevent memory leaks
       return () => { clearInterval(intervalInstance) }
    },[])
    

    It will work, but it’s not an ideal solution. Here are some reasons why:

    1. Token check – just the fact, that you have a token does not mean you are logged in. The token should be checked if it’s valid, not outdated, from the correct issuer and so on. There are some guides how to do this more properly: oAuth guide, another quite comprehensive guide. You can find a ton of them on the internet.
    2. Security – storing token in localStorage is convenient, but comes with many, many drawbacks. It can leak easily, so it’s not a recommended way. You can read more in this SO post.
    3. Periodical checks – these are far from ideal. Thanks to React reactivity system and automatic updates on e.g. setState or React.Context value changes, we should rather look for a solution, that after logging in and obtaining the token will cause automatic rerender of the <App/> e.g. by updating React.Context value, setting the state. The clue is, that you should trigger this rerender on successful login by setting up a value that will update <App/> component. React will take care of rest related to rerendering and showing Sidebar.
    Login or Signup to reply.
  2. You need to re-render the component as user successfully logs in / logs out.
    Use useEffect dependancy stated as in below code.

    Check this updated code.

    import React, { useEffect, useState } from "react";
    import { Route, Routes } from "react-router";
    import Home from "./Routes/Home";
    import Contact from "./Routes/Contact";
    import Enroll from "./Routes/Enroll";
    import Login from "./Routes/Login";
    import SideNavbar from "./Components/InnerComponents/SideNavbar";
    import Profile from './Routes/Admin/Profile';
    import Notice from './Routes/Admin/Notice';
    import Result from './Routes/Admin/Result';
    import StudentList from "./Routes/Admin/StudentList";
    import TeacherList from "./Routes/Admin/TeacherList";
    import Classroom from "./Routes/Admin/Classroom";
    import NoticeState from "./context/notices/NoticeState";
    import NewAccount from "./Routes/Admin/NewAccount.js";
    import UserState from "./context/user/UserState";
    
    function App() {
      const [isLoggedIn, setIsLoggedIn] = useState(false);
    
      useEffect(() => {
        const token = localStorage.getItem('token');
        setIsLoggedIn(!!token);
      }, []);
    
      const handleLogin = () => {
        setIsLoggedIn(true);
      };
    
      const handleLogout = () => {
        localStorage.removeItem('token');
        setIsLoggedIn(false);
      };
    
      return (
        <div className="App">
          <UserState>
            <NoticeState>
              <Routes>
                <Route element={<NewAccount />} exact path="/newaccount" />
                <Route element={<Profile />} exact path="/profile" />
                <Route element={<Notice />} exact path="/notice" />
                <Route element={<Result />} exact path="/result" />
                <Route element={<TeacherList />} exact path="/teacherList" />
                <Route element={<Classroom />} exact path="/classroom" />
                <Route element={<StudentList />} path="/classroom/:classID" />
    
                <Route element={<Home />} exact path="/" />
                <Route element={<Contact />} exact path="/contact" />
                <Route element={<Enroll />} exact path="/enroll" />
                <Route
                  element={<Login onLogin={handleLogin} />}
                  exact path="/login"
                />
              </Routes>
              <Navbar />
              {isLoggedIn && <SideNavbar onLogout={handleLogout} />}
            </NoticeState>
          </UserState>
        </div>
      );
    }
    
    export default App;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search