Issue
I have this React Component for Privates routes. I want to check if user is logged in, so I check if jwt is in local storage and if token is not expired. If this doesn't happen I want to log user out, since token is expired.
I have a react warning that says I can't return a function and Component at the same level. What would be the best approach to achieve this?
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
import dayjs from 'dayjs';
import { useUserStore } from '@store/userStore';
import Main from '@layouts/Main';
function PrivateRoutes() {
const { expiresIn, removeUser } = useUserStore();
const now = dayjs();
const handleRemoveUser = () => {
removeUser();
};
return window.localStorage.getItem('jwt') && dayjs(expiresIn).isAfter(now) ? (
<Main>
<Outlet />
</Main>
) : (
<>
{handleRemoveUser}
<Navigate to='/login' />
</>
);
}
export default PrivateRoutes;
I have tried using handler functions, arrow functions but not sure how to approach this situation
Solution
The render function of a React component is to be considered a pure function, there should be no unintentional side-effects during the render such as calling functions to de-authenticate users. For this you'll need to use the useEffect
hook to issue an intentional side-effect as part of the normal React component lifecycle.
Compute the authentication condition and use as a dependency for a useEffect
hook that conditionally calls removeUser
, while at the same time conditionally returning valid JSX in the function return.
Example:
function PrivateRoutes() {
const { expiresIn, removeUser } = useUserStore();
const now = dayjs();
const jwt = window.localStorage.getItem('jwt');
const isNotExpired = dayjs(expiresIn).isAfter(now);
const isAuth = jwt && isNotExpired;
React.useEffect(() => {
if (!isAuth) {
removeUser();
}
}, [isAuth, removeUser]);
return isAuth
? (
<Main>
<Outlet />
</Main>
)
: <Navigate to="/login" replace />;
}
Answered By - Drew Reese
Answer Checked By - - Gilberto Lyons (ReactFix Admin)