Home > OS >  Async Route Element Return in React JS
Async Route Element Return in React JS

Time:08-24

Getting Error: Guard(...): Nothing was returned from render. This usually means a return statement is missing.

I want to call the API in my guard component before returning the element to Route Element to check if the logged in user have access to specific route or not.

For that, I have implemented a guard. Here's the route file code.

export default function Router() {
    return (
        <Routes>
            <Route path="organizations">
                <Route path="list" element={<Guard><ListOrganization /></Guard>} />
        </Routes >
    );
}

Guard component code

const Guard = (props) => {
    fetch('https://apiToCheckPermission.com')
    .then(response => {
        if (response.isPermission) {
            return props.children;
        }
    })
};

export default Guard;

It's kind of a thing that, I want to implement async route element. But React is throwing error if I don't immediately return the element from Guard.

Can anyone please tell How to solve this error?

CodePudding user response:

Try to define a state to handle the permission and useEffect to load the data:

const Guard = (props) => {
  const [hasPermission, setHasPermission] = useState(false);

  useEffect(async () => {
    const response = await fetch('https://apiToCheckPermission.com');
    setHasPermission(response.isPermission);
  }, []);

  if (!hasPermission) return <>Unauthorized</>;

  return props.children;
};

export default Guard;

CodePudding user response:

If Guard is supposed to be a React component then it needs to always return valid JSX. The Guard currently returns nothing. I.E. it would need to return something from the Promise chain and then return that from the function body.

To resolve use some local state to hold a confirmed/verified permission value and conditionally render the children prop or a fallback. A typical route protection implementation will wait to confirm a user's access then render either the children or redirect to the login page with the location being accessed so the user can be redirected back after authenticating.

Example:

const Guard = ({ children }) => {
  const location = useLocation();

  const [hasPermission, setHasPermission] = React.useState(); // <-- initially undefined

  React.useEffect(() => {
    );
    fetch('https://apiToCheckPermission.com')
      .then(response => {
        setHasPermission(response.isPermission);
      });
  }, []);

  if (hasPermission === undefined) {
    return null; // or loading indicator, spinner, etc
  }

  return hasPermission
    ? children
    : <Navigate to="/login" replace state={{ from: location }} />;
};
  • Related