'Why logout navlink doesn't work with localStorage?

I'm trying to use localStorage in order to connect/disconnect users on my website. I tried to manage this with a condition on click on the navbar (it concerns the latest NavLink component).In a middleware I recover the token (verified with a console.log). When the user wants to log out I would like to empty the token and display "LogIn" instead of "LogOut" . But that has no effect. The token is indeed null at the time of the click but impossible to disconnect. It is also impossible to connect again because the modal is not displayed because there is always "logout". Thank you very much for your help! AppHeader (index.js)

// import Bootsrap-react's components
import {
  Container,
  Navbar,
  Nav,
  Modal,
  Button,
  Form,
} from 'react-bootstrap';
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { LinkContainer } from 'react-router-bootstrap';
import logo from 'src/assets/images/logo.png';
import { fetchAllEvents } from '../../actions/events';
import { setSelectedRegionId } from '../../actions/regions';
import { setSelectedGenreId } from '../../actions/genres';
import { changeEmail, changePassword, logIn } from '../../actions/user';
import './appHeader.scss';

const AppHeader = () => {
  const dispatch = useDispatch();
  const [show, setShow] = useState(false);
  const emailValue = useSelector((state) => state.user.email);
  const passwordValue = useSelector((state) => state.user.password);
  const token = localStorage.getItem('token');

  const callLogin = () => {
    let isLogged;
    if (token !== null) {
      isLogged = 'Logout';
    }
    else {
      isLogged = 'Log In';
    }
    return isLogged;
  };
  const handleClose = () => setShow(false);
  const handleOpen = () => setShow(true);
  const logOut = () => localStorage.setItem('token', null);
  return (
    <div>
      <Navbar id="mainNav" expand="lg">
        <Container id="navbar-container">
          <LinkContainer to="/">
            <Navbar.Brand> <img src={logo} alt="logo" height="60" />
            </Navbar.Brand>
          </LinkContainer>
          <LinkContainer to="/">
            <Nav.Link>
              <h2 className="navbar-title">Concert'o</h2>
            </Nav.Link>
          </LinkContainer>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav " placement="right">
            <Nav className="flex-grow-1 justify-content-evenly">
              <LinkContainer
                to="/"
                onClick={() => {
                  dispatch(setSelectedGenreId());
                  dispatch(setSelectedRegionId());
                }}
              >
                <Nav.Link className="navlink-header">Accueil</Nav.Link>
              </LinkContainer>
              <LinkContainer to="/genres">
                <Nav.Link className="navlink-header">Genres</Nav.Link>
              </LinkContainer>
              <LinkContainer to="/regions">
                <Nav.Link className="navlink-header">Regions</Nav.Link>
              </LinkContainer>
              <LinkContainer
                to="/tous-les-evenements"
                onClick={() => {
                  dispatch(setSelectedGenreId());
                  dispatch(setSelectedRegionId());
                  dispatch(fetchAllEvents());
                }}
              >
                <Nav.Link className="navlink-header">Tous les événements</Nav.Link>
              </LinkContainer>
              <Nav.Link
                className="navlink-header "
                onClick={() => {
                  if (token !== null) {
                    dispatch(logOut());
                  }
                  else {
                    dispatch(handleOpen());
                  }
                }}
              >{callLogin()}
              </Nav.Link>
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar>
      <Modal show={show} onHide={handleClose}>
        <Modal.Header closeButton>
          <Modal.Title>Me connecter</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <Form>
            <Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
              <Form.Label>Email</Form.Label>
              <Form.Control
                type="email"
                placeholder="[email protected]"
                autoFocus
                email={emailValue}
                onChange={(event) => {
                  // console.log(event.target.value);
                  dispatch(changeEmail(event.target.value));
                }}
              />
            </Form.Group>
            <Form.Group
              className="mb-3"
              controlId="exampleForm.ControlTextarea1"
            >
              <Form.Label>Mot de passe</Form.Label>
              <Form.Control
                type="password"
                password={passwordValue}
                onChange={(event) => {
                  // console.log(event.target.value);
                  dispatch(changePassword(event.target.value));
                }}

              />
            </Form.Group>
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button
            variant="secondary"
            onClick={() => {
              dispatch(logIn());
              dispatch(handleClose());
            }}
          >
            Valider
          </Button>
          <LinkContainer
            to="/inscription"
          >
            <Button onClick={handleClose} variant="primary">
              Pas encore inscrit ? Cliquez ici
            </Button>
          </LinkContainer>
        </Modal.Footer>
      </Modal>
    </div>

  );
};
export default AppHeader;

USER REDUCER

import { CHANGE_EMAIL, CHANGE_PASSWORD, SAVE_USER_DATA } from '../actions/user';

export const initialState = {

  email: '',
  password: '',
  username: '',
  token: null,
  errorMessage: '',
};

const user = (state = initialState, action = {}) => {
  switch (action.type) {
    case CHANGE_EMAIL:
      return {
        ...state,
        email: action.value,
      };
    case CHANGE_PASSWORD:
      return {
        ...state,
        password: action.value,
      };
    case SAVE_USER_DATA:
      return {
        ...state,
        username: action.nickname,
        token: action.token,
      };
    default:
      return state;
  }
};
export default user;



Solution 1:[1]

Why the token isn't null

You can only store a string in localStorage, so when you set it to null and check later if the value is null, the answer is no because localStorage is now equal to the string "null", not null.

What you can do instead is removing the token altogether :

localStorage.removeItem("token");

Then simply check if token exists :

let isLogged;
if (token) {
  isLogged = "Logout";
} else {
  isLogged = "Log In";
}
return isLogged;

You can also shorten your code with the following :

return token ? 'Logout' : 'Log In'

Moreover

You are using dispatch, which is a function for updating the store by passing in an action object, however dispatch(logOut());, dispatch(handleOpen()); and dispatch(handleClose()); are not passing in an object, these functions don't return anything. Meaning you might (and should) run into errors because of this, since that's an improper use of the dispatch function.

Read more about dispatch here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1