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
Try changing the useEffect like this
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.