skip to Main Content

I have been working on this authentication for weeks now, and finally throwing in the towel as it has become a beast that is untamable. From my code below, I want the Sign Out and Sign In | Register links to change state if user is not authenticated. In other words, if isAuthenticated && userId is false I want the Sign In | Register link to to show, but if isAuthenticated && userId is true I want the Sign Out link to show without having to refresh the page.

The issue is that they change state only after I refresh the page. Below is a copy of the code:

import { useState, useEffect } from "react";
import Link from "next/link";
import { Client, Account } from 'appwrite';
import { useAuth } from "../pages/AuthContext";
import { useRouter } from 'next/navigation';

export default function Navbar() {
  const { logOut, logIn } = useAuth();
  const [user, setUser] = useState(null);
  const [errors, setErrors] = useState('');
  const [userId, setUserId] = useState("undefined");
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [showSignOutLink, setShowSignOutLink] = useState(false);
  const router = useRouter();

  const client = new Client();
  const account = new Account(client);

  client
    .setEndpoint(process.env.NEXT_PUBLIC_ENDPOINT)
    .setProject(process.env.NEXT_PUBLIC_PROJECT_ID);

  useEffect(() => {
    const checkSession = async () => {
      try {
        const response = await account.getSession("current");
        if (response.current && response.userId) {
          setUserId(response.userId);
          setIsAuthenticated(true);
        } else {
          setIsAuthenticated(false);
        }
      } catch (error) {
        setIsAuthenticated(false);
      }
    };

    const fetchUserData = async () => {
      try {
        const response = await account.get();
        if (response) {
          setUser(response.name);
        }
      } catch (error) {
        setErrors(error.message);
      }
    };

    checkSession();

    if (isAuthenticated) {
      fetchUserData();
    }
  }, [isAuthenticated]);

  const handleLogout = async () => {
    try {
      await account.deleteSession('current');
      logOut();
      router.push('/');
    } catch (error) {
      console.error("Logout Error:", error);
    }
  };

  useEffect(() => {
    setShowSignOutLink(isAuthenticated && userId !== null);
  }, [isAuthenticated, userId]);

return (
<> 
   <Menu>
        {showSignOutLink ? (
         <button onClick={handleLogout}>Sign Out</button>
        ) : (
         <Link href="/login">Sign In | Register </Link>
        )}
   </Menu>
</>
 )
}

2

Answers


  1. Try changing the useEffect like this

    useEffect(() => {
         if (isAuthenticated && userId !== null) {
             setShowSignOutLink(true);
         } else setShowSignOutLink(false);
      }, [isAuthenticated, userId]);
    
    Login or Signup to reply.
  2. The effect dealing with the "setIsAuthenticated" is executed
    1.) if the Navbar component is rendered the first time (mounted)
    2.) if "isAuthenticated" state changes (based on dependencies of the effect)

    Since this state "isAuthenticated" is only changed within this effect, this effect will not run anymore (without "refresh the page" or the "key" of the Navbar component changes, if there is one used).

    It seems to be a solution to call "setIsAuthenticated(false)" within the handleLogout callback.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search