conditionally render different header

Viewed 34

I am new to react js and try to create basic login UI, after user login the header of the UI change automatically. For testing purpose, I just want to remove the login option from the header, later, I may add more options such as logout and others. Here is my code

import { useState,useEffect } from 'react';
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';


const Header = () => {
  const [localtoken, setLocaltoken] = useState(null);
  useEffect(() => {
    const jwt_token= localStorage.getItem('jwt_token');
    if (jwt_token) {
      setLocaltoken(jwt_token);
    }},[]);
  console.log(localtoken)  
  if (!localtoken){
    console.log(localtoken)
    return (
      <Navbar bg="primary" variant="dark">
      <Container>
        <Navbar.Brand href="home">Navbar</Navbar.Brand>
        <Nav>
          <Nav.Link href="home">Home</Nav.Link>
          <Nav.Link href="login">Login</Nav.Link>
          <Nav.Link href="register">Register</Nav.Link>
        </Nav>
      </Container>
    </Navbar>)}
  else {
    return (
      <Navbar bg="primary" variant="dark">
      <Container>
        <Navbar.Brand href="home">Navbar</Navbar.Brand>
        <Nav>
          <Nav.Link href="home">Home</Nav.Link>
          <Nav.Link href="register">Register</Nav.Link>
        </Nav>
      </Container>
    </Navbar>)
  }
}

export default Header

The problem for me is after I login, the header still show "Home Login Register", I have to click either "Home" or "Login" again to make the header change to the required status.

Before login After login Prefer status straight after login

1 Answers

According to your code, on mount, the Header decides whether he should be in logged in mode or not based on some data in the localStorage. But if it starts in unlogged mode, how would the Header know when the user logs in? With the current code, the Header is totally unaware of the login state since there is only a localStorage check at mount time (and the Header is likely to be mounted only once when the page loads).

Here are a few possibilities to fix this:

// After you login and update the localStorage, force a page reload (kinda awful)
location.reload();

// Regularly check your localStorage (pretty bad) in your Header Component
  useEffect(() => {
    const interval = setInterval(() => {
      const jwt_token= localStorage.getItem('jwt_token');
      if (jwt_token) {
        setLocaltoken(jwt_token);
        clearInterval(interval);
      }
   }, 100);
   return () => clearInterval(interval);
 },[]);

// Add a isLoggedIn props to the Header and update that prop after the login call
const App = () => {
  const {isLoggedIn, setIsLoggedIn} = useState(!!localStorage.get('token'));
  const loginFn = async (credentials: any) => { const resp = await fetchToken(credentials); if (resp is successful) setIsLoggedIn(true)}
  return <><Header isLoggedIn={isLoggedIn}/><LoginPage login={loginFn}></>
}

const Header = (props) => {
    return 
      <Navbar bg="primary" variant="dark">
      <Container>
        <Navbar.Brand href="home">Navbar</Navbar.Brand>
        <Nav>
          <Nav.Link href="home">Home</Nav.Link>
          {!props.isLoggedIn && <Nav.Link href="login">Login</Nav.Link>}
          <Nav.Link href="register">Register</Nav.Link>
        </Nav>
      </Container>
    </Navbar>

Or another option (the best one?) might be to use a proper state manager such as redux. Connect your Header component to the store and rerender is when isLoggedIn changes. When your login process successfully gets a token, update the store with isLoggedIn = true.

Related