Search code examples
reactjsreact-hooksuse-statereact-componentreact-lifecycle

Misunderstand using useState react hook - don't work properly


I'm trying to implement private routes according user role permissions. Here is my code:

App.js or routes.js:

<PrivateRoutes path="/equipments" role="hasEquipments" component={(props) => <EquipmentsList {...props} />} />
<PrivateRoutes path="/users/options" role="hasUsers" component={(props) => <UsersOptions {...props} />} />

PrivateRoutes component:

const PrivateRoutes = ({ role, ...rest }) => {
  const [permissions, setPermissions] = useState(false);
  const user = JSON.parse(localStorage.getItem('@TEST:userInfo'));

  useEffect(() => {
    async function loadRoles() {
      try {
        if (user !== undefined) {
          const response = await api.get(`/users/role/${user.nickname}`);
          const userPermissions = response.data.permissions;

          if (role === undefined) {
            setPermissions(false);
          }

          if (role === 'hasEquipments') {
            if (userPermissions.hasEquipments.state) {
              setPermissions(true);
            }
          }

          if (role === 'hasUsers') {
            if (userPermissions.hasUsers.state) {
              setPermissions(true);
            }
          }
        }
      } catch (err) {
        console.log(err);
      }
    }

    loadRoles();
  }, [role]);

  const userLogged = () => {
    if (localStorage.getItem('@TEST:tokenJwt')) {
      return true;
    } else {
      return false;
    }
  }

  if (!userLogged()) {
    return <Redirect to="/" />;
  }

  if (!role && userLogged()) {
    return <Route {...rest} />;
  }
    
  return (
    <>
      {console.log(permissions)}
      {permissions ? <Route {...rest} /> : <Redirect to="/" />}
    </>
  )
};

export default PrivateRoutes;

response.data e.g. from /users/role/${user.nickname} post:

{
  hasEquipments: {
    actions: {post: true, put: true, delete:: false}
    state: true,
  },   
  hasUsers: {
    actions: {post: false, put: false, delete:: false}
    state: false,
  }
}

Following the response.data e.g, i would have access of /equipments path. No matter what, i'm always redirect to '/', permissions hook is always false. In last return, if i only print {console.log(permissions)}, commenting {permissions ? <Route {...rest} /> : <Redirect to="/" />} line, then permissions hook is true. I think i'm misunderstading some lifecycle concepts here.

Any tips how to achieve this?


Solution

  • The redirection is made even before the call to the api is made. useEffect is called after the component has rendered. A solution would be to add an intermediary value, like null or you let it undefined, it's just a way to know whether the call to the api has already been made or not.

    const [permissions, setPermissions] = useState(null);
    
    // ...
    
    if (permissions === null) return null
    
    // ...
    
    {permissions ? <Route {...rest} /> : <Redirect to="/" />}