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?
CodePudding user response:
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 />;
}
}
