I am creating a small app that uses AWS Authentication (it provides convenient handling of social and non-social logins). On the redirect flow from AWS, I subscribe to logged-in event inside useEffect and create user via POST to my server.
Unfortunately, useEffect runs twice (I put a log there to confirm). Another SO post suggested that useEffect should be pure and <React.StrictMode> is causing this. What would be the suggested flow to create the account here?
My code so far:
export default function LoginRedirect() {
const _userService = new UserService();
const navigator = useNavigate();
useEffect(() => {
console.log("activating useEffect in LoginRedirect");
const getUserAndProcess = async (eventCancelToken: () => void) => {
try {
console.log("processing user...");
const currentUser = await Auth.currentAuthenticatedUser() as CognitoUser
if(currentUser != null) eventCancelToken() //stop listening to any more auth events
else return;
const userSession = currentUser.getSignInUserSession();
const idToken = userSession?.getIdToken().getJwtToken();
const accessToken = userSession?.getAccessToken().getJwtToken();
const refreshToken = userSession?.getRefreshToken().getToken();
if(idToken === undefined || accessToken === undefined || refreshToken === undefined) {
throw new Error("idToken, accessToken, or refreshToken is undefined");
}
const processUserResult = await _userService.processUser(
{
IdToken: idToken
} as ProcessUser
);
console.log(currentUser);
console.log(processUserResult);
navigator("/");
} catch(error) {
console.warn(error);
}
};
const authListenerCancelToken = Hub.listen("auth", ({ payload: { event, data }}) => {
switch (event) {
case 'signIn':
console.log('Sign in happened!', data);
getUserAndProcess(authListenerCancelToken)
.catch(console.error);
break;
case 'cognitoHostedUI':
console.log('Sign in happened via cognito hosted UI!', data);
break;
case "signOut":
break;
case 'signIn_failure':
case 'cognitoHostedUI_failure':
console.log('Sign in failure', data);
break;
}
});
getUserAndProcess(authListenerCancelToken).catch(console.error);
});
return (
<div className="h-screen w-full grid place-items-center">
<div className="grid place-items-center">
<h1 className="text-lg my-3">Logging you in...</h1>
<div className="loading loading-ring loading-lg justify-self-center"></div>
</div>
</div>
);
}
2
Answers
Can yo check with second parameter of useEffect as blank array so it will get call once page loaded
useEffect(() => {
}, []);
you can try :
Try this, but I don’t understand why it’s not a button that simply engages the function?
Otherwise, I’ve just extracted the useEffect logic, added an empty dependency array and added a variable to know whether or not the useEffect has already been called.
Linster unmount function in docs
When using useEffect, think about the dependency table and ask yourself whether anything needs to be removed after disassembly (listener in particular).