cannot set text input ref - react-native

I'm trying to switch focus between inputs on onSubmitEditing but I can't manage to pass the ref props from my custom text input to the main component.
The console log I've put in the ref doesn't log anything.
const MyCustomInput = (props) => {
<View>
<FormInput
{...props}
editable={!props.disabled}
selectTextOnFocus={!props.disabled}
disable={props.disabled}
displayOnly={props.displayOnly}
small={props.small}
placeholderTextColor={'#AFAFAF'}
/>
</View>
}
<Controller
control={control}
render={({field: {onChange, onBlur, value, ref}}) => (
<MyCustomInput
onBlur={onBlur}
onChangeText={(value: string) => onChange(value)}
value={value}
ref={(r: any) => {
console.log('r', r);
ref(r);
inputRef.current = r;
}}
/>
)}
name="myInput"
/>

Solved, I was missing a forward ref in my custom input
const MyCustomInput = fowardRef((props, ref) => {
<View>
<FormInput
{...props}
ref={ref}
editable={!props.disabled}
selectTextOnFocus={!props.disabled}
disable={props.disabled}
displayOnly={props.displayOnly}
small={props.small}
placeholderTextColor={'#AFAFAF'}
/>
</View>
)}

Related

React Native - add specific clearButton on input field when the keyboard is open

I am trying to create a specific clear button to use on both ios and android devices. I have created a reusable component for the several fields I have. When I press the fields since the keyboard opens the X button shows in all fields not only the field I have pressed. In the code below emptyField is a value set in a parent component.
const [keyboardShow, setKeyboardShow] = useState<boolean>(false);
useEffect(() => {
const showKeyboard = Keyboard.addListener('keyboardDidShow', () => {
setKeyboardShow(true);
});
const hideKeyboard = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardShow(false);
});
return () => {
showKeyboard.remove();
hideKeyboard.remove();
};
}, []);
<TouchableComponent>
<TextInput
key={currencyTypeId}
ref={forwardRef}
style={styles.input}
onChangeText={onChangeText}
value={inputValue}
editable={editable}
autoCorrect={false}
autoCompleteType='off'
returnKeyType={returnKeyType}
placeholder={placeholder}
placeholderTextColor={placeholderColor}
keyboardType={keyboardType}
/>
</TouchableComponent>
{inputValue.length > 0 && keyboardShow && (
<View style={styles.customButton}>
<TouchableOpacity onPress={emptyField}>
<CloseIcon width={12} height={12}/>
</TouchableOpacity>
</View>
)}
Seems 'keyboardDidShow' and 'keyboardDidHide' events triggered in each reusable component.
You can try another approach. Just use onBlur and onFocus events. It's isolated for each component:
<TouchableComponent>
<TextInput
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
key={currencyTypeId}
ref={forwardRef}
style={styles.input}
onChangeText={onChangeText}
value={inputValue}
editable={editable}
autoCorrect={false}
autoCompleteType="off"
returnKeyType={returnKeyType}
placeholder={placeholder}
placeholderTextColor={placeholderColor}
keyboardType={keyboardType}
/>
</TouchableComponent>
{inputValue.length > 0 && isFocused && (
<View style={styles.customButton}>
<TouchableOpacity onPress={() => {}}>
<CloseIcon width={12} height={12} />
</TouchableOpacity>
</View>
)}

KeyboardAvoidingView, ScrollView and Flatlist in a form

I have a form where I am using KeyboardAvoidingView and ScrollView so that when a user clicks on an input field the screen will scroll to that particular field
Within my form I have an input field that is searchable and I am using a FlatList to display the results for the user to choose from. Currently I am getting the error:
VirtualizedLists should never be nested inside plain ScrollViews
I've looked at many posts around this but am yet to find a solution (unless I've missed something):
1 - How to put FlatList inside of the ScrollView in React-native?
2 - FlatList inside ScrollView doesn't scroll
3 - How to make a FlatList scrollable inside of a ScrollView in react native?
This is what I have so far:
export const SignUpMember = ({navigation}) => {
const renderHeader = formikProps => {
return (
<>
<FormField
keyboardType={'default'}
fieldName={'firstName'}
label={'First Name'}
/>
<FormField
keyboardType={'default'}
fieldName={'lastName'}
label={'Last Name'}
/>
<FormField
onChangeText={text => {
formikProps.values.clubName = text;
searchItems(text);
}}
value={formikProps.values.clubName}
keyboardType={'default'}
fieldName={'clubName'}
label={'Club Name'}
placeholder={'Search Club By Name...'}
/>
</>
);
};
const renderFooter = formikProps => {
return (
<>
<FormField
keyboardType={'phone-pad'}
fieldName={'telephone'}
label={'Telephone'}
/>
<FormField
keyboardType={'email-address'}
fieldName={'email'}
label={'Email'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'password'}
label={'Password'}
type={'password'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'passwordConfirmation'}
label={'Confirm Password'}
type={'password'}
/>
<Button
mt="2"
bg="brand.blue"
type="submit"
onPress={formikProps.handleSubmit}>
Sign Up
</Button>
</>
);
};
return (
<KeyboardAvoidingView
keyboardVerticalOffset={headerHeight}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<ScrollView
_contentContainerStyle={styles.container}
nestedScrollEnabled={true}>
<Box p="1" py="8" w="90%" maxW="290">
<VStack space={3} mt="5">
<Formik
initialValues={initialFormValues}
onSubmit={values => handleFormSubmit(values)}
validationSchema={userValidationSchema}>
{formikProps => (
<View>
<FlatList
nestedScrollEnabled={true}
data={flatListData}
renderItem={({item}) => (
<Pressable
onPress={() => {
formikProps.values.clubName = item.name;
setFlatListData([]);
}}>
<Text style={styles.flatList}>{item.name}</Text>
</Pressable>
)}
keyExtractor={item => item.name}
ListHeaderComponent={renderHeader(formikProps)}
ListFooterComponent={renderFooter(formikProps)}
/>
</View>
)}
</Formik>
</VStack>
</Box>
</ScrollView>
</KeyboardAvoidingView>
);
};
export default SignUpMember;
How can I piece this together?

Formik handleChange - use hooks

before installing Formik, my input looked like so:
const [search, setSearch] = useState('');
....
<View style={styles.profileEditContainer__top}>
<TextInput
style={styles.profileEditContainer__form}
autoCapitalize="none"
placeholder="Enter what you want to create.."
placeholderTextColor={Colors.formPlaceHolderDefault}
name="search"
type="search"
value={search}
onChangeText={(e) => setSearch(e)}
autoCorrect={false}
defaultValue={search}
/>
<Button
disabled={!search}
title="Create"
onPress={(e) => {
createNewCar(e);
}}
/>
</View>
in onChangeText, I would set every character I typed to a state prop called search. With every key that I typed, an API called would be made to get some data from the db.
for example:
if I typed h into the input, the db would return 2 cars honda, hyundai
I read that Formik can simplify a lot of the form setup in React, so I downloaded it, however, the handleChange prop from Formik wants to keep track of values.search
<Formik
initialValues={{
search,
}}
onSubmit={(values) => {
console.log('values', values);
}}>
{({ handleChange, handleSubmit, values }) => (
<View style={styles.profileEditContainer__top}>
<TextInput
style={styles.profileEditContainer__form}
autoCapitalize="none"
placeholder="Enter what you want to create.."
placeholderTextColor={Colors.formPlaceHolderDefault}
autoCorrect={false}
value={values.search}
onChangeText={(e) => {
handleChange(values.search);
setSearch(e);
}}
/>
<Button
disabled={!search}
title="Create"
onPress={handleSubmit}
/>
</View>
)}
</Formik>
Now I can't type into the form because value is pointing at values.search instead of search like it did originally.
Question
How do I fire setSearch in onChangeText but also add search into the formik values prop?
you can make use of setFieldValue('search', e.target.value) instead of handleChange() change the code to the following:
<Formik
initialValues={{
search,
}}
onSubmit={(values) => {
console.log('values', values);
}}>
{({ handleChange, handleSubmit, values, setFieldValue }) => (
<View style={styles.profileEditContainer__top}>
<TextInput
style={styles.profileEditContainer__form}
autoCapitalize="none"
placeholder="Enter what you want to create.."
placeholderTextColor={Colors.formPlaceHolderDefault}
autoCorrect={false}
value={values.search}
onChangeText={(e) => {
//handleChange(values.search);
setFieldValue('search', e.target.value)
setSearch(e);
}}
/>
<Button
disabled={!search}
title="Create"
onPress={handleSubmit}
/>
</View>
)}
</Formik>

React-native FlatList component is Not Working

Hello I am a beginner to react-native. I was practicing with a basic app which reads the input from the user and display it in the screen. I am trying to use the FlatList but it is not rendering.
Here is my code
export default function App() {
const [enteredText, setEnteredText] = useState(
""
); /* constant and method with String*/
const [enteredString, setEnteredString] = useState(
[]
); /* constant and method with Array */
const enteredTextHandler = (enteredText) => {
setEnteredText(enteredText);
}; /* Set the entered text to the constant value*/
const addTextHandler = () => {
setEnteredString((currentString) => [
...currentString,
{ id: Math.random().toString(), value: enteredText },
]); /* Add entered text to the array */
};
return (
<View style={styles.mainView}>
<View style={styles.container}>
<TextInput
placeholder="Enter te value"
style={styles.input}
onChangeText={enteredTextHandler}
value={enteredText}
/>
<Button title="Add" onPress={addTextHandler} style={styles.button} />
</View>
<FlatList
data={enteredString}
keyExtractor={(item) => item.id}
renderItem={(itemData) => {
console.log(itemData.item.value);
<View style={styles.listStyle}>
<Text>{itemData.item.value}</Text>
</View>;
}}
/>
</View>
);
}
It might be because you've reused the variable name enteredText in your enteredTextHandler. I think the way it's set up it'll always set enteredText to blank.
Try using a different name for the text argument:
const enteredTextHandler = newText => {
setEnteredText(newText);
}; /* Set the entered text to the constant value*/
I got the answer
<FlatList
data={enteredString}
keyExtractor={(item, index) => item.id}
renderItem={(itemData) => (
<View style={styles.listStyle}>
<Text>{itemData.item.value}</Text>
</View>
)}
/>
I was written the syntax wrong. previously I used (itemData) => {} but the actual syntax is (itemData) => () . Instead of parantesis I used curly braces that's why it was not displaying.

How to open keyboard on button press in react native?

I have a button and when it is pressed I would like it to open the keyboard and focus on a text input component.
For a minimal code example what I am trying to do is this-
<View>
<AddSomething
textChange={textInput => this.setState({ textInput })}
addNewItem={this.addItem.bind(this)}
textInput={this.state.textInput}
ref={not sure what goes here} //passing these as props to a text input
/>
<FloatingButton tapToAddHandler={this.onFloatingButtonPress.bind(this)} />
</View>
then some helper function where I handle the button press (this.onFloatingButtonPress)
First declare your AddSomething as below :
const AddSomething = React.forwardRef((props, ref) => (
<TextInput
ref={ref}
//your other code
/>
));
Now you can use ref and able to focus your AddSomething component as below:
<View>
<AddSomething
textChange={textInput => this.setState({ textInput })}
addNewItem={this.addItem.bind(this)}
textInput={this.state.textInput}
ref={(ref) => { this.textInputField = ref }}
/>
<FloatingButton tapToAddHandler={this.onFloatingButtonPress.bind(this)} />
</View>
Here is your onFloatingButtonPress method :
onFloatingButtonPress() {
this.textInputField.focus();
}
Proposal a react-hook version :
const inputRef = React.useRef()
return (
<TextInput ref={inputRef} />
<TouchableOpacity onPress={() => inputRef.current.focus()}>
<Text>Press</Text>
</TouchableOpacity>
)