aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.12k forks source link

Amplify SignIn component handleAuthStateChange issue #5825

Closed ccoffman-ebsco closed 4 years ago

ccoffman-ebsco commented 4 years ago

Describe the bug When setting handleAuthStateChange on the AmplifySignIn component, the login works, but the sign in screen does not disappear. Instead it stays and none of the interior components load.

To Reproduce Check out the code snippet.

Expected behavior I expect that once my code in the custom handleAuthStateChange function is complete, the signin component will no longer be visible and my inner components will be.

Code Snippet

export interface IAuthenticationProps {
  children: ReactNode;
}

const Authentication: React.FC<IAuthenticationProps> = (props) => {
  const [authState, setAuthState] = useState("");

  const handleAuthStateChange = (state: string) => {
    console.log(state);
    if (state === "signedin" || state === "signedout") {
      setAuthState(state);
    }
  };

  return (
    <div>
      <AmplifyAuthenticator usernameAlias="email">
        <AmplifySignIn
          usernameAlias="email"
          slot="sign-in"
          handleAuthStateChange={handleAuthStateChange}
        />
        <AmplifySignUp
          usernameAlias="email"
          slot="sign-up"
          formFields={[{ type: "email" }, { type: "password" }]}
        ></AmplifySignUp>

        {authState === "signedin" && <div>{props.children}</div>}
        <div style={{ width: "25%" }}>
          <AmplifySignOut />
        </div>
      </AmplifyAuthenticator>
    </div>
  );
};

export default Authentication;

Screenshots Before sign in, and when submit is pressed it shows the loading spinner on the button image after sign in, it looks the same! image

What is Configured?

Amplify.configure({
  Auth: {
    region: "us-east-1",
    userPoolId: "xxxxxxxxxxxx",
    userPoolWebClientId: "xxxxxxxxxxx",
  },
});

Additional context This is a React solution

jordanranz commented 4 years ago

handleAuthStateChange will override the default behavior to dispatch an event to the AmplifyAuthenticator telling it which underlying component to render. In your case, since the Authenticator doesn't receive this event it will continue to display the state you were previously in.

We are working on a better guide for customizing the auth UI state management. In the meantime, instead of passing in this prop to AmplifySignIn, you may be able to do something like the withAuthenticator: https://github.com/aws-amplify/amplify-js/blob/master/packages/amplify-ui-react/src/withAuthenticator.tsx#L18-L37. You should have access to the onAuthUIStateChange function used here using

import { onAuthUIStateChange } from '@aws-amplify/ui-components'

We may also, add a callback function prop to AmplifyAuthenticator to assist managing Auth UI state changes as well.

ccoffman-ebsco commented 4 years ago

I was unable to import onAuthUIStateChange to my project. I got an error that it does not exist. I was also unsure how you meant for me to use it? Would I call it from my handlAuthStateChange method?

matteofigus commented 4 years ago

We may also, add a callback function prop to AmplifyAuthenticator to assist managing Auth UI state changes as well.

That would be nice

jordanranz commented 4 years ago

@ccoffman-ebsco which version of @aws-amplify/ui-react are you using? Also note the import:

import { onAuthUIStateChange } from '@aws-amplify/ui-components'

rather than:

import { onAuthUIStateChange } from '@aws-amplify/ui-react'

Sorry, I could have posted a snippet for you. You can use a React Hook hook similar to the code snippet I posted like:

// ...
import { onAuthUIStateChange } from '@aws-amplify/ui-components'

export interface IAuthenticationProps {
  children: ReactNode;
}

const Authentication: React.FC<IAuthenticationProps> = (props) => {
  const [authState, setAuthState] = React.useState();

  React.useEffect(() => {
    return onAuthUIStateChange(newAuthState => {
        setAuthState(newAuthState)
    });
  }, []);

  return (
    <div>
      <AmplifyAuthenticator usernameAlias="email">
        <AmplifySignIn
          usernameAlias="email"
          slot="sign-in"
        />
        <AmplifySignUp
          usernameAlias="email"
          slot="sign-up"
          formFields={[{ type: "email" }, { type: "password" }]}
        ></AmplifySignUp>

        {authState === "signedin" && <div>{props.children}</div>}
        <div style={{ width: "25%" }}>
          <AmplifySignOut />
        </div>
      </AmplifyAuthenticator>
    </div>
  );
};
matteofigus commented 4 years ago

Thanks for your help @jordanranz your snippet worked fine for a very similar scenario I was trying to fix.

I have to say that we may want to improve the docs for the handleAuthStateChange because it's not very clear that you need to handle that! In my case, I had an <AmplifySignIn> working fine, and only today I realised that the app was broken when creating new users (because they need to reset their password on first access, and the reset password component wasn't automatically showing while the user was stuck in the signin phase with no errors!).

I wonder if we could consider making the default behaviour for that handler to also dispatch the event to the Authenticator? That sounds more intuitive to me but I'm sure I may be missing something! :)

lucasMobee commented 4 years ago

Just ran into exactly this, thanks for posting!

ccoffman-ebsco commented 4 years ago

@jordanranz Thank you for the code snippet it did help! But, I am getting this erorr: image

These are from my package json:

"@aws-amplify/ui-react": "^0.2.5", "aws-amplify": "^3.0.10",

Do you know what this might be?

ccoffman-ebsco commented 4 years ago

Nevermind, I added this to my dependencies and was able to make it work!

"@aws-amplify/ui-components": "^0.5.0"

Thanks for all of your help!

stephendmalloy commented 4 years ago

Had the same issue here. This worked for me.

popschoolonline commented 4 years ago

For Angular you can implement the onAuthUIStateChange in your constructor:

import { onAuthUIStateChange } from '@aws-amplify/ui-components'  

constructor() {
    onAuthUIStateChange(newAuthState  => {
      this.handleCustomAuthState(newAuthState)
    })
  }

handleCustomAuthState(authState: AuthState) {
    //Your custom implementation
}
github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.