Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay in useContext React JS

In my React App, when the user logins, a token is generated (JWT) after that it is stored in LocalStorage.

Once everything is done, in order to maintain user login for different routes, I'm using useContext.

I want to show logout button if the user is logged in (in reality it appears, but after 2 seconds) in short, I could see login / register button and after 2 seconds it shows the logout button.

Here is my code:

Main.js

export default function Main() {

const [userData,setUserData] = useState(
  {token:undefined,
  user:undefined,}
);

useEffect(()=>{
const checkLoggedIn = async() =>{
  const token = localStorage.getItem("auth-token");
  if(token===null) {localStorage.setItem("auth-token","");
  token = "";}
  const tokenRes = await Axios.post("http://localhost:5000/user/tokenIsValid",
  null,
  {headers:{"x-auth-token":token}})
if(tokenRes.data){
  const userRes = await Axios.get("http://localhost:5000/user/",{headers:{"x-auth-token":token}})
  setUserData({
    token,
    user:userRes.data
  })
}
  };

  checkLoggedIn();
}

,[])



  return (
    <BrowserRouter>
      <UserContext.Provider value={{userData,setUserData}}>
      <ThemeProvider theme={theme}>
      
        <Navbar />

        <Switch>
          <Route exact path="/" component={Home} />

          <Route exact path="/login" component={Login} />
          <Route exact path="/register" component={Register} />
                  <Route exact path="/recover" component={Recover} />
          <Route exact path="/privacy-policy" component={PrivacyPolicy} />
          <Route
            exact
            path="/terms-of-service"
            component={TermsAndConditions}
          />
          <Route exact path="/contact" component={Contact} />
          <Route exact path="/faqs" component={FAQs} />
          <Route component={Error} />
        </Switch>

        <myFooter />
        </ThemeProvider>
        </UserContext.Provider>
      
    </BrowserRouter>
  );
}

Then here is my Navbar.js

export default function Navbar(){
  const { userData,setUserData } = useContext(UserContext);
  const classes = useStyles();
  const logout = () =>{
    setUserData({
      token:undefined,
      user:undefined
    })
    localStorage.setItem("auth-token","")
  }
  return(
<>

<AppBar position="static" color="transparent">
  <Toolbar>
    <Typography  className={classes.doBold}>
      <Link to="/" className={classes.noLinkStyle}><img src={require('../images/logo.png')} height="auto" width="150px" className={classes.AlignVertical} alt="Logo"/></Link>
    </Typography>
    <ButtonGroup size="small" variant="outlined" color="secondary">
      {
        userData.user!==undefined?<myLoginMenu  style={{marginRight:'20px'}}/>:<> <Link to="/login" className={classes.noLinkStyle}><myButton variant="contained" content="Login" icon="login"/></Link>
        <Link to="/register" className={classes.noLinkStyle}><myButton variant="contained" primary content="Register" icon="register" /></Link></>
      }



</ButtonGroup>
  </Toolbar>

</AppBar>

</>
  )
}

And at last UserContext.js

import {createContext} from 'react';
export default createContext(null);

And here is my Login Route

router.get("/login", async (req, res) => {
  try {
    const { email, password } = req.body;
    if (!email || !password) {
      return res.status(400).json({ msg: "Something is missing." });
    }
    const student = await Student.findOne({ email: email });
    if (!student)
      return res
        .status(400)
        .json({ msg: "No account reigstered with this email." });

    const isMatch = await bcrypt.compare(password, student.password);
    if (isMatch) {
      
      const token = jwt.sign({id:student._id},process.env.JWT_TOKEN)
      res.json({
          token,
          user:{
              id:student._id
          }
      })
    } else return res.status(400).json({ msg: "Incorrect Password" });
  } catch (error) {
    res.status(500).json({ errorReceived: error });
  }
});
like image 999
Fara Avatar asked Feb 27 '26 22:02

Fara


1 Answers

Edited: Sorry I didn't read your question well. Yes, what you're facing is quite normal because at the first render, you're not logged in so the Log out button would appear to be Log in. What you can do is:

  1. Add a server-side renderer. So when your application run on server-side it runs the authentication to get the data of user then returns to client side.
  2. Hide (or animate the Log in/Log out button until the useEffect finishes running) so the user's experience would be more smooth.
like image 166
Pho Huynh Avatar answered Mar 02 '26 03:03

Pho Huynh