How to refactor common react code for a sign in redirect?

25 views Asked by At

I'm working on a React application and a lot (but not all) of the pages include this code:

export default function MyPage() {
  const { isAuthenticated, loginWithRedirect } = useAuth0<User>();

  const handleSignIn = async () => {
    await auth.login(loginWithRedirect);
  };

  if (!isAuthenticated) {
    return <SignIn onSignIn={handleSignIn} />;
  }

  // ...
}

Looking for some advice on how to refactor this so it isn't duplicated across multiple pages. Would a hook be appropriate? Or some kind of parent component wrapper???

1

There are 1 answers

0
Adam Jenkins On BEST ANSWER

Have you looked at the built in HOC withAuthenticationRequired?

If you need more customization you could effectively recreate withAuthenticationRequired but can customize it a bit more:

Component wrapper works great:

const RequiresAuthenticatedUser = ({children}) => {
    const { isAuthenticated, isLoading, error, loginWithRedirect } = useAuth0<User>();

    const shouldRequireLogin = !isLoading && !isAuthenticated && !error

    useEffect(() => {
       if(!shouldRequireLogin) return;
       auth.login(loginWithRedirect)
    },[shouldRequireLogin,loginWithRedirect])

    if(error) {
      // something went wrong, return an error message
      return <>Error</>
    }

    if(isLoading) {
      return null; // or a spinner, I think null is appropriate
    }

    if(!isAuthenticated) {
       auth.login(loginWithRedirect)
       return nulll;
    }

    return <>{children}</>
}

Can be used like this:

function MyPage() {
  ...
}

export default () => <RequiresAuthenticatedUser><MyPage/></RequiresAuthenticatedUser/>

You can use the above to create a nifty little HOC to wrap your components in:

const requiresAuthenticatedUser = (Cmp) => (props) => <RequiresAuthenticatedUser><Cmp {...props}/></RequiredAuthenticatedUser>

function MyPage() {
 ...
}

export default requiresAuthenticatedUser(MyPage)

One reason I strongly advocate for a wrapping component (or HOC) instead of a hook is because it moves the logical concerns of "do I even have a user" outside of the components that require a user. Otherwise, it's extremely common for "I'm not sure if I have a user yet" logic to pollute components that really should only be concerned with rendering the user they know they have.