0

i have a function in AuthAPI.js

and it has the following code

const isLoggedIn = () => {
  const token = localStorage.getItem("token");
  return token ? true : false;
};

i want to show login and logout navbar item conditionally, when user logouts and logins

Navlink.js code ->

import React, { useEffect, useState } from "react";
import { NavLink } from "react-router-dom";

import { isLoggedIn } from "../APIHandler/AuthAPI";

import styles from "./NavLinks.module.css";

export default function NavLinks() {
  const [isLoggedInState, setIsLoggedInState] = useState(false);

  useEffect(() => {
    async function init() {
      const token = await localStorage.getItem("token");
      console.log({ token });
      token ? setIsLoggedInState(true) : setIsLoggedInState(false);
    }
    init();
  }, []);

  useEffect(() => {
    console.log({ isLoggedInState });
    if (isLoggedInState == false) {
      localStorage.removeItem("token");
    }
  }, [localStorage]);

  const handleLogout = (e) => {
    e.preventDefault();
    console.log("called handle logout");
    // localStorage.removeItem("token");
    setIsLoggedInState(false);
  };

  return (
    <>
      <li className={styles.main_nav__item}>
        <NavLink to="/">HOME</NavLink>
      </li>

      <li className={styles.main_nav__item}>
        <NavLink to="/blogs">BLOGS</NavLink>
      </li>
      {!isLoggedInState && (
        <li className={styles.main_nav__item}>
          <NavLink to="/login">LOGIN</NavLink>
        </li>
      )}
      {isLoggedInState && (
        <li className={styles.main_nav__item}>
          <button onClick={handleLogout} className={styles.logout}>
            LOGOUT
          </button>
        </li>
      )}
    </>
  );
}


  • here ,when user clicks on logout , the token is being removed, but the component is not loaded to reflect the changes,

  • how do I reflect the changes in navlink ,when user clicks on logout, it is possible if I use a state variable, but I am using local storage to tell whether user is logged in or not.

  • I have tried this answer

  • but it didn't work

Rohan Devaki
  • 2,931
  • 1
  • 14
  • 22

1 Answers1

1

I won't go into the design/best practices. But this should give you some idea how to achieve what you are aiming for.

This is based on my own encounter with a login/logout problem that I addressed in the past. Sharing so that this might help in some way. The steps here are somewhat generic so that anyone can relate to his/her scenario. :

You would need context and hooks.

You can do something like this in your App.js file :

export const AuthContext = React.createContext();

const initialState = {
    isAuthenticated: <<your logic here where you decide based on local storage sth like localStorage.getItem(<<sth based on your usecase>>) >>? true : false,
    user: null,
    token: null,
};

Then in the same App.js use a reducer like this:

const reducer = (state, action) => {
    switch (action.type) {
        case "LOGIN":
            // if (action.remember) {
            localStorage.setItem("user", JSON.stringify(action.payload));
            // }
            return {
                ...state,
                isAuthenticated: true,
                user: action.payload,
            };
        case "LOGOUT":
            window.localStorage.clear();
            return {
                ...state,
                isAuthenticated: false,
                user: null,
            };
        default:
            return state;
    }
};

Inside your App function :

function App() {
    const [state, dispatch] = React.useReducer(reducer, initialState);

    useEffect(() => {
        return () => {
        };
    }, [state.isAuthenticated]);

Wrap the entire content of return inside AuthContext.Provider :

return (
<AuthContext.Provider value={{state, dispatch}}>

//here sits your layout/BrowserRouter and other things that you typically would expect.

</AuthContext.Provider>
);

Setting the LOGIN or LOGOUT state for our dispatch

You can set the state to LOGIN or LOGOUT wherever you are handling the authentication.

For your case looks liek you are doing this inside AuthAPI.js.

So for LOGIN call the dispatch method.

Below is a typical example of using in a then block of an axios or similar rest call. But as said earlier you can call this anywhere where you are doing post authentication setup. for your case it can be inside of your isLoggedIn function :

dispatch({
          type: "LOGIN",
          payload: res.data,
          remember: rememberMe,
        });

Similarly for LOGOUT, sth like calling the dispatch method on click of logout button:

onClick={() =>
          dispatch({
            type: "LOGOUT",
          })
        }

Now that we have the setup ready, how to use all of this in our components ??

Try to relate below with your Navlink.js component. But this would work for any other components too.

And then you can all the above in any other component(like your Navlink.js component) by just importing the AuthContext from App:

import { AuthContext } from "../App";

then get hold of the state and dispatch method :

  const { dispatch } = React.useContext(AuthContext);
  const { state } = React.useContext(AuthContext);

then check the login state by sth like :

  const [loginStatus, setLoginStatus] = useState(state.isAuthenticated);

Then based on the state, conditionally render components, sth like below inside your return statement:

return (

    <>
       <div>
       <<your other components here>>
       </div>

        {!state.isAuthenticated ? (
                  <Button
                    onClick={showLoginModalWindow}
                    icon={<FIIcons.FiLogIn />}
                  >
                    Login
                  </Button>
                ) : ( <div> ...someother component...</div>)}
    <>

);

I am really not an expert react developer. So constructive feedback are always welcome. Still learning and trying to help with whatever little I know.

EDIT 1 : START

For your specific use case, using ternary operator this would be :

return (
    <>
      <li className={styles.main_nav__item}>
        <NavLink to="/">HOME</NavLink>
      </li>

      <li className={styles.main_nav__item}>
        <NavLink to="/blogs">BLOGS</NavLink>
      </li>


      {!state.isAuthenticated ? (
        <li className={styles.main_nav__item}>
          <NavLink to="/login">LOGIN</NavLink>
        </li>
      ) : (
        <li className={styles.main_nav__item}>
          <button onClick={handleLogout} className={styles.logout}>
            LOGOUT
          </button>
        </li>
      )}
    </>
  );

EDIT 1 : END

Asif Kamran Malick
  • 2,409
  • 3
  • 25
  • 47