I am a bit new in react native and I have got into an interesting situation. I have a Login screen in which there are two fields;
- Mobile number.
- password
On Login button press I am executing two functions :
- handleMobileInput() - which check if the mobile number is valid. 2 handlePasswordInput() - which will check if password is valid.
I also have a global state named 'errors' initially it is empty object({}) and 'setErrors' function to update it. Full code looks like this
const [errors, setErrors] = useState({});
const handleLogin = () => {
handleMobileInput(mobileNo);
handlePasswordInput(password);
if (errors.mobError || errors.passError) {
return;
}
}
const handleMobileInput = (mobileNo) => {
if (!mobileNo) {
const x = { ...errors, mobError: 'mobile no. is required'}
console.log(x); //outputs correctly
setErrors(x);
console.log(errors); //output incorrectly even when I click login again and again
} else if (mobileNo.length !== 10) {
setErrors({ ...errors, mobError: 'mobile no must be of 10 digits'});
} else {
setErrors({ ...errors, mobError: ''});
}
setMobileNo(mobileNo);
}
const handlePasswordInput = (password) => {
if (!password) {
setErrors({ ...errors, passError: 'password is required'})
} else if (password.length < 5) {
setErrors({ ...errors, passError: 'password must be 6 characters long'});
} else {
setErrors({ ...errors, passError: ''})
}
setPassword(password);
}
Now when I click login , handleLogin() function executes and it first validates mobile Number
since mobile number is empty(because I haven't touched it, I presses Login directly), variable x inside handleMobileInput() updated as { mobError: 'mobile no is required }
which is correct. But when I try to set the variable x to my state, it doesn't update it and return empty object. But it does update password state correctly. Now my final state 'errors' looks like this
{
passError: 'password is required'
}
but I need it as
{
mobError: 'mobile no is required',
passError: 'pass is required'
}
No matter How many times I presses the login button this state remains same and state for mobError never gets updated. All these functions are inside my main functional component. Full code looks like this
import React from 'react';
import { View, Text, StyleSheet, TextInput, TouchableOpacity, CheckBox } from 'react-native';
import { Button, Card, Title, Divider } from 'react-native-paper';
import { AntDesign } from '@expo/vector-icons';
import { default as globalStyles } from '../globalStyles';
import { useState } from 'react';
const LoginScreen = ({ navigation }) => {
const [errors, setErrors] = useState({});
const [mobileNo, setMobileNo] = useState('');
const [password, setPassword] = useState('');
const handleMobileInput = (mobileNo) => {
if (!mobileNo) {
const x = { ...errors, mobError: 'mobile no. is required'}
console.log(x); //outputs correctly
setErrors(x);
console.log(errors); //output incorrectly even when I click login again and again
} else if (mobileNo.length !== 10) {
setErrors({ ...errors, mobError: 'mobile no must be of 10 digits'});
} else {
setErrors({ ...errors, mobError: ''});
}
setMobileNo(mobileNo);
}
const handlePasswordInput = (password) => {
if (!password) {
setErrors({ ...errors, passError: 'password is required'})
} else if (password.length < 5) {
setErrors({ ...errors, passError: 'password must be 6 characters long'});
} else {
setErrors({ ...errors, passError: ''})
}
setPassword(password);
}
const handleLogin = () => {
handleMobileInput(mobileNo);
handlePasswordInput(password);
if (errors.mobError || errors.passError) {
return;
}
}
return (
<View style={globalStyles.viewStyle}>
<Card style={globalStyles.cardStyle}>
<Card.Content>
<Title style={globalStyles.title}>Welcome to Mshur</Title>
<Divider style={{...globalStyles.divider, ...globalStyles.bgColorPrimary}}></Divider>
</Card.Content>
<View style={globalStyles.inputView}>
<AntDesign name="user" size={24} color="white" style={{...globalStyles.inputIconStyle, ...globalStyles.bgColorPrimary}}/>
<TextInput
style={globalStyles.inputStyle}
placeholder="enter mobile number"
placeholderTextColor="grey"
keyboardType="numeric"
onChange = {(e) => {
handleMobileInput(e.nativeEvent.text);
}}>
</TextInput>
</View>
{
errors.mobError ?
(<Text style={globalStyles.error}>{errors.mobError}</Text>)
: null
}
<View style={{...globalStyles.inputView, ...globalStyles.marginTop_1}}>
<AntDesign name="lock" size={24} color="white" style={{...globalStyles.inputIconStyle, ...globalStyles.bgColorPrimary}}/>
<TextInput
style={globalStyles.inputStyle}
placeholder="enter password"
placeholderTextColor="grey"
onChange = {(e) => {
handlePasswordInput(e.nativeEvent.text);
}}
>
</TextInput>
</View>
{
errors.passError ?
(<Text style={globalStyles.error}>{errors.passError}</Text>)
: null
}
<View style={styles.loginHelp}>
<View style={globalStyles.checkboxContainer}>
<CheckBox value={true}></CheckBox>
<Text style={{fontSize: 13}}>Remember me?</Text>
</View>
<TouchableOpacity style={globalStyles.TouchableOpacityStyle}>
<Text style={{color: 'grey'}}>Forgot Password</Text>
</TouchableOpacity>
</View>
<Button
style={{marginHorizontal: 15, ...globalStyles.bgColorPrimary, ...globalStyles.buttonStyle}}
mode="contained"
contentStyle = {{ height: 40 }}
onPress={() => handleLogin()}>
Login
</Button>
<Button
style={{marginHorizontal: 15, ...globalStyles.bgColorSeconday, ...globalStyles.marginTop_1, ...globalStyles.buttonStyle}}
mode="contained"
contentStyle = {{ height: 40 }}
onPress={() => navigation.navigate('SignUp')}>
New user? sign up
</Button>
</Card>
</View>
)
}
const styles = StyleSheet.create({
loginHelp: {
display:'flex',
flexDirection: 'row',
justifyContent: 'space-between',
marginHorizontal: 15,
},
});
export default LoginScreen;