skip to Main Content

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


  1. Can yo check with second parameter of useEffect as blank array so it will get call once page loaded

    useEffect(() => {
    }, []);

    Login or Signup to reply.
  2. you can try :

    export default function LoginRedirect() {
        const _userService = new UserService();
        const navigator = useNavigate();
    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);
                }
            };
    
    
    
    let ignore;
    
    
        useEffect(() => {
            console.log("activating useEffect in LoginRedirect");
           if(ignore){
             return;
            }:
            
            // maybe unMount this listener 
            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;
                }
            });
    // maybe get .then() for not lauch again if 
            getUserAndProcess(authListenerCancelToken).catch(console.error);
    
    return () => {
    ignore= true;
    authListenerCancelToken() 
    // for unmount listener when useEffect is Unmounted
    }
    
        }, []);
    
    
      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>
      );
    }
    

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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search