I have an issue with focusing the next input in React Native. I use just one input called GeneralTextInput.tsx in the whole app.
In this example I have 2 inputs ==> 1.Group Name, 2.Group Description
So I give some props in the parent to this component:
<View style={classes.formContainer}>
<Text style={classes.label}>{t("group.name-your-group")}</Text>
<GeneralTextInput
width={"100%"}
returnKeyType={"next"}
isDoneReference={false}
deleteIcon
startIcon={"account-multiple"}
bordered={true}
placeholder={t("form.placeholders.groupName")}
value={props.newGroupName}
onChange={(val: string) => {
props.setNewGroupName(val);
if (val.length > 25) {
props.setNewGroupNameError(t("form.validations.max-25-char"));
}
if (val.length <= 25) {
props.setNewGroupNameError(undefined);
}
}}
/>
<Text style={classes.label}>{t("group.describe-your-group")}</Text>
<GeneralTextInput
width={"100%"}
returnKeyType={"done"}
isDoneReference={true}
isDismissed={true}
startIcon={"text"}
bordered={true}
isMultiLine={true}
numberOfLines={3}
placeholder={t("form.placeholders.groupDescription")}
value={props.newGroupDescription}
onChange={(val: string) => {
props.setNewGroupDescription(val);
if (val.length > 30) {
props.setNewGroupDescriptionError(t("form.validations.max-30-char"));
}
if (val.length < 30) {
props.setNewGroupDescriptionError(undefined);
}
}}
/>
</View>
And this is my GeneralTextInput.tsx What should I give to the input as a ref and how should I focus on it?
import * as React from "react";
import {
NativeSyntheticEvent,
Platform,
StyleProp,
TextInputFocusEventData,
TextStyle,
View,
ViewStyle,
TextInput,
ImageStyle,
Pressable,
} from "react-native";
import { makeStyles, IStyledComponent } from "../../assets/theme/installation";
import { IconButton, Text, useTheme } from "react-native-paper";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import FontAwesome5Icon from "react-native-vector-icons/FontAwesome5";
import { theme } from "../../assets/theme/DefaultTheme";
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
export interface IGeneralTextInputProps
extends IStyledComponent<GeneralTextInputStyles> {
readonly value: string | undefined;
readonly placeholder?: string;
readonly onChange: (newValue: string) => void;
readonly onBlur?: (e: NativeSyntheticEvent<TextInputFocusEventData>) => void;
readonly isPassword?: boolean;
readonly autoCapitalize?: boolean;
readonly error?: string;
readonly startIcon?: string;
readonly startIconFA5?: string;
readonly endIcon?: string;
readonly deleteIcon?: boolean;
readonly disabled?: boolean;
readonly disabledInputText?: boolean;
readonly bordered?: boolean;
readonly isMultiLine?: boolean;
readonly width?: number | string;
readonly numberOfLines?: number;
readonly keyboardType?: string;
readonly isGratitude?: boolean;
readonly autoCorrect?: boolean;
readonly selectedMeasureUnit?: string;
readonly returnKeyType?: string;
readonly isDoneReference?: boolean;
readonly isDismissed?: boolean;
}
export const GeneralTextInput: React.FC<IGeneralTextInputProps> = (
props: IGeneralTextInputProps,
) => {
const classes = useStyles(props);
const { fonts, colors } = useTheme();
const [isPressed, setIsPressed] = React.useState(false);
const [isPasswordVisible, setPasswordVisible] = React.useState(false);
const groupNameRef = React.useRef<HTMLInputElement>(null);
const groupDescRef = React.useRef<HTMLInputElement>(null);
return (
<View style={classes.container}>
<TouchableWithoutFeedback>
<View style={classes.root}>
<TextInput
ref={() => (props.isDoneReference ? groupDescRef : groupNameRef)}
onSubmitEditing={() => {
groupDescRef.current?.focus();
}}
blurOnSubmit={props.isDoneReference ? true : false}
keyboardType={
props.keyboardType === "numpad" ? "numeric" : "default"
}
autoCorrect={props.autoCorrect}
multiline={props.isMultiLine}
numberOfLines={props.numberOfLines}
maxLength={props.isGratitude ? 300 : 50}
editable={!props.disabled}
onBlur={props.onBlur}
autoCapitalize={
props.autoCapitalize != undefined ? "words" : "none"
}
secureTextEntry={
props.isPassword == undefined ? false : !isPasswordVisible
}
style={
props.disabledInputText
? classes.disabledTextInput
: classes.textInput
}
value={props.value}
placeholder={props.placeholder}
placeholderTextColor={fonts.text.small.color}
onTouchEnd={() => setIsPressed(true)}
onChangeText={(value) => props.onChange(value)}
returnKeyType={
props.returnKeyType === "next"
? "next"
: props.returnKeyType === "done"
? "done"
: "default"
}
/>
</View>
</TouchableWithoutFeedback>
</View>
);
};
CodePudding user response:
If I understand correctly forwardRef ist what you are looking for.
import * as React from "react";
import {
NativeSyntheticEvent,
Platform,
StyleProp,
TextInputFocusEventData,
TextStyle,
View,
ViewStyle,
TextInput,
ImageStyle,
Pressable,
} from "react-native";
import { makeStyles, IStyledComponent } from "../../assets/theme/installation";
import { IconButton, Text, useTheme } from "react-native-paper";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import FontAwesome5Icon from "react-native-vector-icons/FontAwesome5";
import { theme } from "../../assets/theme/DefaultTheme";
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
export interface IGeneralTextInputProps
extends IStyledComponent<GeneralTextInputStyles> {
readonly value: string | undefined;
readonly placeholder?: string;
readonly onChange: (newValue: string) => void;
readonly onBlur?: (e: NativeSyntheticEvent<TextInputFocusEventData>) => void;
readonly isPassword?: boolean;
readonly autoCapitalize?: boolean;
readonly error?: string;
readonly startIcon?: string;
readonly startIconFA5?: string;
readonly endIcon?: string;
readonly deleteIcon?: boolean;
readonly disabled?: boolean;
readonly disabledInputText?: boolean;
readonly bordered?: boolean;
readonly isMultiLine?: boolean;
readonly width?: number | string;
readonly numberOfLines?: number;
readonly keyboardType?: string;
readonly isGratitude?: boolean;
readonly autoCorrect?: boolean;
readonly selectedMeasureUnit?: string;
readonly returnKeyType?: string;
readonly isDoneReference?: boolean;
readonly isDismissed?: boolean;
}
export const GeneralTextInput: React.forwardRef<IGeneralTextInputProps> = (
props: IGeneralTextInputProps,
ref: any
) => {
const classes = useStyles(props);
const { fonts, colors } = useTheme();
const [isPressed, setIsPressed] = React.useState(false);
const [isPasswordVisible, setPasswordVisible] = React.useState(false);
const groupNameRef = React.useRef<HTMLInputElement>(null);
const groupDescRef = React.useRef<HTMLInputElement>(null);
return (
<View style={classes.container}>
<TouchableWithoutFeedback>
<View style={classes.root}>
<TextInput
ref={() => (props.isDoneReference ? groupDescRef : groupNameRef)}
onSubmitEditing={() => {
groupDescRef.current?.focus();
}}
blurOnSubmit={props.isDoneReference ? true : false}
keyboardType={
props.keyboardType === "numpad" ? "numeric" : "default"
}
autoCorrect={props.autoCorrect}
multiline={props.isMultiLine}
numberOfLines={props.numberOfLines}
maxLength={props.isGratitude ? 300 : 50}
editable={!props.disabled}
onBlur={props.onBlur}
autoCapitalize={
props.autoCapitalize != undefined ? "words" : "none"
}
secureTextEntry={
props.isPassword == undefined ? false : !isPasswordVisible
}
style={
props.disabledInputText
? classes.disabledTextInput
: classes.textInput
}
value={props.value}
placeholder={props.placeholder}
placeholderTextColor={fonts.text.small.color}
onTouchEnd={() => setIsPressed(true)}
onChangeText={(value) => props.onChange(value)}
returnKeyType={
props.returnKeyType === "next"
? "next"
: props.returnKeyType === "done"
? "done"
: "default"
}
/>
</View>
</TouchableWithoutFeedback>
</View>
);
};));
const ref = React.createRef();
<GeneralTextInput
ref={ref}
width={"100%"}
returnKeyType={"next"}
isDoneReference={false}
deleteIcon
startIcon={"account-multiple"}
bordered={true}
placeholder={t("form.placeholders.groupName")}
value={props.newGroupName}
onChange={(val: string) => {
props.setNewGroupName(val);
if (val.length > 25) {
props.setNewGroupNameError(t("form.validations.max-25-char"));
}
if (val.length <= 25) {
props.setNewGroupNameError(undefined);
}
}}
/>
CodePudding user response:
Try not to handle your reference in GeneralTextInput.tsx
, handle reference for both differently in your main file and pass onSubmitEditing
props from the main file too.
To your second GeneralTextInput
create a inputRef
and focus that on your first GeneralTextInput
component
<GeneralTextInput
onSubmitEditing = {() => inputRef.current.focus()}
...
>
<GeneralTextInput
ref = { inputRef }
...
>
Then simply pass them as a prop to your GeneralTextInput.tsx
file. Hope this works for you
<TextInput
ref={props.ref || null}
onSubmitEditing={props.onSubmitEditing || null}
...
>
Hope this works for you.