-
Notifications
You must be signed in to change notification settings - Fork 54
Open
Description
Hi guys!
I have the following React context provider:
import React, { useState, useEffect, createContext } from 'react';
import auth from '@react-native-firebase/auth';
import { useValidation } from 'react-native-form-validator';
import { validationMsgs, validationRules } from './auth.validation';
import { ErrorText } from '../../features/auth/components/auth.styles';
export const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
const [ currentUser, setCurrentUser ] = useState(null);
const [ passResetCode, setPassResetCode ] = useState('');
const [ isLoading, setIsLoading ] = useState(false);
const [ error, setError ] = useState(null);
const [ displayName, setDisplayName ] = useState('');
const [ emailAddress, setEmailAddress ] = useState('');
const [ password, setPassword ] = useState('');
const [ passwordMatch, setPasswordMatch ] = useState('');
const { validate, getErrorsInField, isFormValid } =
useValidation({
state: {
displayName,
emailAddress,
password,
passwordMatch,
},
messages: validationMsgs,
});
const onLoginUser = async (email: string, pass: string) => {
setIsLoading(true);
try {
await auth().signInWithEmailAndPassword(email, pass);
} catch (e: any) {
setError(e.toString());
} finally {
setIsLoading(false);
}
};
// ...many other wrappers around various Firebase Auth functions, such as createUserWithEmailAndPassword
const validateField = (field, numLines) => {
const rules = {};
rules[field] = validationRules[field];
const isValid = validate(rules);
return isValid ? null : getErrorsInField(field).map((e, i) => (
<ErrorText key={i} numberOfLines={numLines}>
{e.replace(/[A-Z]/g, letter => ` ${letter.toLowerCase()}`)
.replace(/^[a-z]/, letter => `${letter.toUpperCase()}`)}
</ErrorText>
));
};
useEffect(() => {
return auth().onAuthStateChanged(user => {
if (user) {
setCurrentUser(user);
}
setIsLoading(false);
});
}, []);
return (
<AuthContext.Provider
value={{
isAuthenticated: !!currentUser,
currentUser,
displayName,
emailAddress,
isLoading,
error,
password,
passwordMatch,
isFormValid,
onLoginUser,
onRegisterUser,
onLogoutUser,
onSendResetEmail,
onResetPassword,
setDisplayName,
setEmailAddress,
setError,
setPassword,
setPasswordMatch,
validateField,
}}>
{children}
</AuthContext.Provider>
);
};
And the following consumer of this context:
import React, { useContext, useState } from 'react';
import { ScrollView } from 'react-native';
import { ActivityIndicator, Button, Colors, TextInput } from 'react-native-paper';
import { AuthContext } from '../../../services/auth/auth.context';
import { ErrorText } from '../components/auth.styles';
import { StyledText } from '../../../components/typography/text.component';
export const LoginScreen = ({ navigation }) => {
const { emailAddress, error, isLoading, isFormValid, onLoginUser,
password, setEmailAddress, setPassword, validateField,
} = useContext(AuthContext);
const [ fieldErrors, setFieldErrors ] = useState({});
const onSubmit = () => {
if (isFormValid()) {
onLoginUser(emailAddress, password);
}
};
return (
<StyledText fontSize="h5" marginTop={'55%'} marginBottom="16px">
Meals 2 U
</StyledText>
<ScrollView>
<TextInput
label="Email address"
value={emailAddress}
textContentType="emailAddress"
keyboardType="email-address"
autoCapitalize="none"
onChangeText={e => {
setEmailAddress(e);
setFieldErrors({ ...fieldErrors, emailAddress:
validateField('emailAddress', 2) });
}} />
{fieldErrors.emailAddress}
<TextInput
label="Password"
value={password}
textContentType="password"
secureTextEntry
autoCapitalize="none"
onChangeText={p => {
setPassword(p);
setFieldErrors({ ...fieldErrors, password:
validateField('password', 6) });
}} />
{fieldErrors.password}
{error && (
<ErrorText numberOfLines={3}>{error}</ErrorText>
)}
{isLoading ? (
<ActivityIndicator
animating={true}
color={Colors.blue300}
/>
) : (
<>
<Button
icon="lock-open-outline"
mode="contained"
onPress={() => onSubmit()}
disabled={!emailAddress || !password || !isFormValid()}>
Login
</Button>
<Button
icon="account-plus"
mode="contained"
onPress={() => {
setEmailAddress('');
setPassword('');
navigation.navigate('Register');
}}>
Register
</Button>
<Button
icon="lock-reset"
isLastButton={true}
mode="contained"
onPress={() => {
setEmailAddress('');
setPassword('');
navigation.navigate('Reset Password');
}}>
Reset Password
</Button>
</>
)}
</ScrollView>
);
};
This all works great, except that I have to enter two characters into either of the TextInput
s before getErrorsInField
actually returns any error messages.
Stepping through the code I can see that the validate
function is returning false straight away (i.e. after typing a single character), but this has no effect on getErrorsInField
until another character is typed.
Is this intended behaviour? If so, why?! It seems to me as though anyone would expect errors to be returned immediately!
In any case, how can I fix this behaviour? MTIA 😄.
Metadata
Metadata
Assignees
Labels
No labels