Skip to content

Authenticator does not rerender on useState prop change #6598

Open
@zfz7

Description

@zfz7

Before creating a new issue, please confirm:

On which framework/platform are you having an issue?

React

Which UI component?

Authenticator

How is your app built?

Create React App

What browsers are you seeing the problem on?

Firefox

Which region are you seeing the problem in?

NA

Please describe your bug.

I have successfully created an Authenticator component that supports both OTP and Username / PW, however to switch between the modes requires a full page reload. I have a boolean prop otp that controls the visibility of the password input box. However when I call setOtp the component does not re render; unless I do a full page reload.

Unsuccessful attempts to fix it:

  • Tried to use the key prop
  • useMemo
  • Separated out various parts as components

Temporary solution:

  • Store the OTP value in local storage and reload the page each time the selection changes...
  • Causing the entire page to flash

What's the expected behaviour?

It re renders the Authenticator component when props change.

Help us reproduce the bug!

I attached the failing code; fundamentally I am trying to avoid a full page reload when changing the otp status.

Code Snippet

import { Authenticator, Button, useAuthenticator } from "@aws-amplify/ui-react";
import { signIn, SignInInput, signUp, SignUpInput } from "aws-amplify/auth";
import { useEffect, useState } from "react";

export function LoginWindow() {
  // const [otp, setOtp] = useState(false); // This useState change should render the component
  const [otp, setOtp] = useState(() => {
    const savedOtp = localStorage.getItem("otp");
    return savedOtp === "true";
  });

  useEffect(() => {
    localStorage.setItem("otp", otp.toString());
  }, [otp]);

  return (
    <Authenticator
      variation="modal"
      initialState={"signIn"}
      components={{
        SignIn: {
          Footer() {
            const { toForgotPassword } = useAuthenticator();
            return (
              <>
                <Button
                  variation="link"
                  size="small"
                  onClick={() => {
                    setOtp(!otp);
                    window.location.reload(); //Why do we need to reload the page?
                  }}
                >
                  {otp ? "Sign with Password" : "Sign without Password"}
                </Button>
                <Button
                  variation="link"
                  size="small"
                  onClick={toForgotPassword}
                >
                  Forgot Password
                </Button>
              </>
            );
          },
        },
      }}
      loginMechanisms={["email"]}
      signUpAttributes={["family_name", "given_name"]}
      formFields={{
        signIn: {
          username: {
            placeholder: "Enter Your Email Here",
            isRequired: true,
            label: "Email",
          },
          password: {
            type: otp ? "hidden" : "password",
            label: "Password",
            labelHidden: otp,
            placeholder: "Enter Your Password Here",
            isRequired: !otp,
          },
        },
        signUp: {
          given_name: {
            order: 1,
            placeholder: "Enter Your First Name",
            isRequired: true,
            label: "First Name",
          },
          family_name: {
            order: 2,
            placeholder: "Enter Your Last Name",
            isRequired: true,
            label: "Last Name",
          },
          email: {
            order: 3,
            placeholder: "Enter Your Email",
            isRequired: true,
            label: "Email",
          },
          password: {
            type: "hidden",
            label: "Password",
            labelHidden: true,
          },
          confirm_password: {
            type: "hidden",
            label: "Confirm Password",
            labelHidden: true,
          },
        },
      }}
      services={{
        async handleSignIn(input: SignInInput) {
          const { username, password } = input;

          return signIn({
            username: username,
            password: password,
            options: {
              authFlowType: otp ? "USER_AUTH" : "USER_PASSWORD_AUTH",
              preferredChallenge: "EMAIL_OTP",
            },
          });
        },
        async handleSignUp(input: SignUpInput) {
          return signUp({
            username: input.username,
            password: input.password,
            options: {
              ...input.options,
              autoSignIn: {
                authFlowType: "USER_AUTH",
                preferredChallenge: "EMAIL_OTP",
              },
              userAttributes: {
                ...input.options?.userAttributes,
                email: input.username,
              },
            },
          });
        },
      }}
    />
  );
}

Console log output

No response

Additional information and screenshots

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    AuthenticatorAn issue or a feature-request for an Authenticator UI Componentpending-maintainer-responseIssue is pending response from an Amplify UI maintainerquestionGeneral question

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions