reactjsreact-nativejsxconditional-rendering

jsx conditional rendering won't update on state change


I want to conditionally render jsx in my AuthForm component and i'm having trouble specifically with the 'isPasscodeEntry' scenario.

My AuthForm component conditionally renders an input form based on the state of isLogin, isForgot, and isPasscodeEntry.

AuthForm is imported and rendered in AuthContent.

AuthContent is conditionally rendered in my LoginScreen component based on the state of based on the state of isLogin, isForgot, and isPasscodeEntry.

isLogin = Login / !isLogin = Sign up / isForgot = enter email > get passcode email / isPasscodeEntry = enter passcode

In LoginScreen i'm console logging the state of isPasscodeEntry and see it change to true when I press 'reset password' but the isPasscodeEntry jsx is not being rendered.

To summarize:

When isForgot is true (Password Reset Flow):

If isForgot is true (Password Reset flow), the isPasscodeEntry JSX will be conditionally rendered when the "Reset Password" button is pressed.

When the "Reset Password" button is pressed (isForgot is true), it will call setIsPasscodeEntry().

When isForgot is false (Login or Signup Flow):

If isForgot is false (Login or Signup flow), the isPasscodeEntry JSX will not be conditionally rendered, and the "Reset Password" button will not be shown. Instead, it will show the "Log In" or "Sign Up" button depending on whether isLogin is true or false.

Here is the jsx for LoginScreen:

function AuthContent({ isLogin, isForgot, isPasscodeEntry, setIsPasscodeEntry, onSignUp, onLogin, onForgot }) {...
return (
        <SafeAreaView style={styles.container}>
            {!isForgot ? (
                <>
                    
                    {isPasscodeEntry ? (
                        <>
                            <AuthContent
                                isLogin={isLogin}
                                isPasscodeEntry={isPasscodeEntry}
                                setIsPasscodeEntry={() => setPasscodeEntry}
                                // onSignUp={signUpHandler}
                                // onLogin={loginHandler}
                            />
                            <View style={styles.forgot}>
                                <Button onPress={() => { setIsForgot(true), setIsLogin(false) }}>
                                    Forgot Password
                                </Button>
                            </View>
                            <View style={styles.buttons}>
                                <Button onPress={() => setIsLogin(!isLogin)}>
                                    {isLogin ? 'Register Here' : 'Login Here'}
                                </Button>
                                {isLoading && <LoadingOverlay />}
                            </View>
                        </>
                    ) : (
                        <>
                            <AuthContent
                                isLogin={isLogin}
                                isPasscodeEntry={isPasscodeEntry}
                                setIsPasscodeEntry={() => setPasscodeEntry}
                                onSignUp={signUpHandler}
                                onLogin={loginHandler}
                            />
                            <View style={styles.forgot}>
                                <Button onPress={() => { setIsForgot(true), setIsLogin(false) }}>
                                    Forgot Password
                                </Button>
                            </View>
                            <View style={styles.buttons}>
                                <Button onPress={() => setIsLogin(!isLogin)}>
                                    {isLogin ? 'Register Here' : 'Login Here'}
                                </Button>
                                {isLoading && <LoadingOverlay />}
                            </View>
                        </>
                    )}
                </>
            ) : (
                <>
                    <AuthContent
                        isLogin={false}
                        isForgot={isForgot}
                        onLogin={forgotHandler}
                        onForgot={forgotHandler}
                        isPasscodeEntry={isPasscodeEntry}
                        setIsPasscodeEntry={() => setPasscodeEntry()}
                    />
                    
                    <View style={styles.buttons}>
                            <Button onPress={() => setIsForgot(false)}>
                            Go Back
                        </Button>
                        {isLoading && <LoadingOverlay />}
                    </View>
                </>
            )}
        </SafeAreaView>
    );
}

export default LoginScreen;

And here is the jsx for AuthForm:

function AuthForm({ isLogin, isForgot, isPasscodeEntry, setIsPasscodeEntry, onSubmit, credentialsInvalid }) {...

return (
        <KeyboardAvoidingView
            style={{ flex: 1 }}
            behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
            keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 100}
        >
            <View style={styles.form}>
                <View>
                    {isForgot ? (
                        <Input
                            label="Email Address"
                            onUpdateValue={updateInputValueHandler.bind(this, 'email')}
                            value={enteredEmail}
                            textInputConfig={{
                                onChangeText: (text) => updateInputValueHandler('email', text),
                                value: enteredEmail,
                            }}
                            keyboardType="email-address"
                            isInvalid={emailIsInvalid}
                        />
                    ) : (
                        <>
                            <Input
                                label="Email Address"
                                onUpdateValue={updateInputValueHandler.bind(this, 'email')}
                                value={enteredEmail}
                                textInputConfig={{
                                    onChangeText: (text) => updateInputValueHandler('email', text),
                                    value: enteredEmail,
                                }}
                                keyboardType="email-address"
                                isInvalid={emailIsInvalid}
                            />

                            {!isLogin && !isForgot && (
                                <Input
                                    label="Confirm Email Address"
                                    onUpdateValue={updateInputValueHandler.bind(this, 'confirmEmail')}
                                    value={enteredConfirmEmail}
                                    keyboardType="email-address"
                                    isInvalid={emailsDontMatch}
                                />
                            )}

                            <Input
                                label="Password"
                                onUpdateValue={updateInputValueHandler.bind(this, 'password')}
                                value={enteredPassword}
                                textInputConfig={{
                                    onChangeText: (text) => updateInputValueHandler('password', text),
                                    value: enteredPassword,
                                    secureTextEntry: true,
                                }}
                                isInvalid={passwordIsInvalid}
                            />

                            {!isLogin && !isForgot && (
                                <Input
                                    label="Confirm Password"
                                    onUpdateValue={updateInputValueHandler.bind(this, 'confirmPassword')}
                                    value={enteredConfirmPassword}
                                    textInputConfig={{
                                        onChangeText: (text) => updateInputValueHandler('confirmPassword', text),
                                        value: enteredConfirmPassword,
                                        secureTextEntry: true,
                                    }}
                                    isInvalid={passwordsDontMatch}
                                />
                            )}

                            {isPasscodeEntry && (
                                // Add your passcode entry component here
                                <>
                                    <Input
                                        label="Enter one-time passcode"
                                        onUpdateValue={updateInputValueHandler.bind(this, 'passcode')}
                                        value={enteredCode}
                                        textInputConfig={{
                                            onChangeText: (text) => updateInputValueHandler('passcode', text),
                                            value: enteredCode,
                                            secureTextEntry: true,
                                        }}
                                        isInvalid={passwordIsInvalid}
                                    />
                                </>
                            )}
                        </>
                    )}
                </View>
                <View style={styles.buttons}>
                    {isForgot ? (
                        // Call setIsPasscodeEntry(true) when isForgot is true
                        <Button onPress={() => { submitHandler(); setIsPasscodeEntry(); }}>
                            Reset Password
                        </Button>
                    ) : (
                        // Call submitHandler when isForgot is false
                        <Button onPress={submitHandler}>
                            {isLogin ? 'Log In' : 'Sign Up'}
                        </Button>
                    )}
                </View>
            </View>
        </KeyboardAvoidingView>
    );
}

export default AuthForm;

Solution

  • Expectation: "If isForgot is true (Password Reset flow), the isPasscodeEntry JSX will be conditionally rendered when the "Reset Password" button is pressed."

    The main problem: Your passcode entry component only renders when isForgot is set to false AND isPasscodeEntry is set to true according to your conditions. This is not the logic you planned in your question.

    Solution: Move the passcode entry component with its conditional rendering to a branch where isForgot is set to true

    I can't show you the exact solution because you have complicated nesting conditions.

    I suggest: