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???
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.