I'm a bit new to react, react-native, react-redux, and react-thunk and am encountering this strange issue which I can't explain.
I have a sign-in component that uses a thunk to authenticate a user. I mapDispatchToProps and apply it to the component but for some reason, every time the component renders, it triggers the thunk and then after every keypress in either input field, the thunk is also triggered. this creates countless calls to the authentication API which all fail.
What would cause this behavior?
const SignIn = ({navigation, signIn}: any): React.ReactElement => {
const [username, setUsername] = React.useState<string>('');
const [password, setPassword] = React.useState<string>('');
const [passwordVisible, setPasswordVisible] = React.useState<boolean>(false);
const onForgotPasswordButtonPress = (): void => {
navigation && navigation.navigate('Forgot Password');
};
const onPasswordIconPress = (): void => {
setPasswordVisible(!passwordVisible);
};
const passwordInput = useRef() as React.MutableRefObject<any>;
return (
<KeyboardAvoidingView>
<ImageOverlay
style={styles.container}
source={require('../assets/images/image-background3.jpg')}>
<SafeAreaView style={styles.container}>
<View style={styles.formContainer}>
<Input
status="control"
placeholder="Username"
autoCapitalize={'none'}
autoCompleteType={'off'}
autoCorrect={false}
autoFocus={false}
icon={PersonIcon}
value={username}
onChangeText={setUsername}
returnKeyType={'next'}
blurOnSubmit={false}
onSubmitEditing={() => passwordInput.current.focus()}
/>
<Input
ref={passwordInput}
style={styles.passwordInput}
status="control"
placeholder="Password"
autoCapitalize={'none'}
autoCompleteType={'off'}
autoCorrect={false}
icon={passwordVisible ? EyeIcon : EyeOffIcon}
value={password}
secureTextEntry={!passwordVisible}
onChangeText={setPassword}
onIconPress={onPasswordIconPress}
onSubmitEditing={() => signIn(username, password)}
/>
<View style={styles.forgotPasswordContainer}>
<Button
style={styles.forgotPasswordButton}
appearance="ghost"
status="control"
onPress={onForgotPasswordButtonPress}>
Forgot your password?
</Button>
</View>
</View>
<Button
style={styles.signInButton}
status="control"
size="large"
disabled={username.length === 0 || password.length === 0}
onPress={signIn(username, password)}>
Sign In
</Button>
</SafeAreaView>
</ImageOverlay>
</KeyboardAvoidingView>
);
};
const mapDispatchToProps = (dispatch: any) => ({
signIn: (username: string, password: string) =>
dispatch(signInThunk(username, password)),
});
export const SignInScreen = connect(
null,
mapDispatchToProps,
)(SignIn);
thunk:
export const signInThunk = (username: string, password: string) => {
return async (dispatch: any) => {
try {
dispatch(isLoading(true));
const userData = await fetch(Providers.auth, {...})
.then(response => response.json())
.then(() => dispatch(isLoading(false)));
if(userData.token){
dispatch(signInAction(userData.token));
dispatch(updateProfileAction(userData));
}
dispatch(isLoading(false));
} catch (error) {
console.error(error);
}
};
};