I am using React Native with Expo and React Native Paper as the styling library.
React Native Paper provides a TextInput Component and a HelperText Component. You can combine these 2 components and have the HelperText show errors or info messages based on the user input in the TextInput component associated with it.
I am trying to create my own custom Component so it encapsulates these two different Components into one, I call my custom Component TextInputWithHelperText.
I am trying to implement this on a Login page that I am working on, and the code that I have is something like this:
LoginPage:
// Imports...
export default function LoginPage() {
const [email, setEmail] = useState('[email protected]');
const [emailHasErrors, setEmailHasErrors] = useState(false);
const [emailValidationErrorMessage, setEmailValidationErrorMessage] = useState('');
const handleLogin = async () => {
// Assume that some email validation results in the following states to change
setEmailHasErrors(true);
setEmailValidationErrorMessage('Invalid Email');
};
return (
<View>
<TextInputWithHelperText
label='Email'
value={email}
onChangeText={input => setEmail(input)}
helperTextVisible={emailHasErrors}
helperTextType='error'
helperTextMessage={emailValidationErrorMessage}
/>
</View>
<View>
<Button mode="contained" onPress={handleLogin}> Login </Button>
</View>
)
TextInputWithHelperText:
import React, { useState } from 'react';
import { TextInput, HelperText } from 'react-native-paper';
export default function TextInputWithHelperText({ ...props }) {
const [value, setValue] = useState(props.value);
return (
<>
<TextInput
label={props.label}
value={props.value}
onChangeText={(inputText) => { setValue(inputText) }}
/>
<HelperText
type={props.helperTextType}
visible={props.helperTextVisible}
>
{props.helperTextMessage}
</HelperText>
</>
)
}
The problem:
The problem occurs on the onChangeText property.
Currently, the way it is, causes the setEmail(input) to never be invoked despite the fact that I can see the input text changing in the UI. This results to the [email protected] value that I set as default, to be sent to the backend as email value each time the login button is clicked.
Things I tried:
Another solution that I tried, was passing to the TextInputWithHelperText Component's onChangeText prop, the onChangeText prop passed down by the parent Component, something like this:
import React, { useState } from 'react';
import { TextInput, HelperText } from 'react-native-paper';
export default function TextInputWithHelperText({ ...props }) {
const [value, setValue] = useState(props.value);
return (
<>
<TextInput
label={props.label}
value={props.value}
onChangeText={props.onChangeText} <--------- THE CHANGE
/>
<HelperText
type={props.helperTextType}
visible={props.helperTextVisible}
>
{props.helperTextMessage}
</HelperText>
</>
)
}
This indeed caused the setEmail(input) to be called each time there is a text change, but in the UI I could only see the last letter that I typed. Also the value of the email was also set to the last letter typed each time.
Question:
How can I keep the UI updating on each text change but also having the email value updating as well in the LoginPage Component?
P.S. I have omitted parts of the code since they were not necessary for the point of the question.