I have a signup/login workflow in React (NextJS), and everything is working correctly; i made a custom hook to remotely check if the user is authenticated based on localStorage jwt:
import React, { useState, useEffect } from 'react';
import axios from '../lib/api';
const useUser = () => {
const [logged, setIsLogged] = useState(false);
const [user, setUser] = useState('');
useEffect(async () => {
const jwt = localStorage.getItem('jwt');
if (!jwt) return;
await axios
.get('/api/users/me', {
headers: {
Authorization: `Bearer ${jwt}`,
},
})
.then((response) => {
setUser(response.data);
setIsLogged(true);
})
.catch((error) => {});
}, []);
return [logged, user, setIsLogged];
};
export default useUser;
This hooks works corectly in 99% of cases, but when i go on login form page, the login form flashes for a sec to logged in users, since the logged status is false before the check is initialized
import React, { useEffect, useState } from 'react';
import useUser from '../../lib/useUser';
import { useRouter } from 'next/router';
import LoginForm from '../../components/LoginForm';
function Login() {
const { push } = useRouter();
const [logged] = useUser();
console.log(ljwt, logged);
if (logged) {
//push('/');
return <p>nored</p>;
}
if (!logged) {
return <LoginForm />;
}
}
export default Login;
how can i avoid this? i tried to pass to useUser the jwt, so it assume the user is logged in while performing the remote check, but it is not really working as expected.
any suggestion?
>Solution :
Don’t render the login form when the login state is still indeterminate.
By the way, useEffect functions can’t be async in themselves, since they need to either return nothing or a cleanup function; async functions always return a promise.
async function getLoginState() {
const jwt = localStorage.getItem("jwt");
if (!jwt) return [false, null];
const resp = await axios.get("/api/users/me", {
headers: {
Authorization: `Bearer ${jwt}`,
},
});
return [true, response.data];
}
/**
* Get user login state.
*
* Returns undefined if the login state is not yet known.
* Returns a 2-item array [loginState, user] otherwise.
* `user` can be null when `loginState` is false.
*/
function useLoginState() {
const [loginState, setLoginState] = useState(undefined);
useEffect(() => {
getLoginState().then(setLoginState);
}, []);
return loginState;
}
function Login() {
const { push } = useRouter();
const loginState = useLoginState();
if (loginState === undefined) {
return <>Loading...</>;
}
const [logged, user] = loginState;
if (logged) {
return <p>Hi, {JSON.stringify(user)}</p>;
} else {
return <LoginForm />;
}
}