使用 Typescript 使用 useRef 反应本机文本输入焦点
React Native Text Input focus with useRef using Typescript
我在 React Native 中聚焦下一个输入时遇到问题。我在整个应用程序中只使用一个名为 GeneralTextInput.tsx 的输入。
在此示例中,我有 2 个输入 ==> 1.Group 名称, 2.Group 描述
所以我在父级中给这个组件一些道具:
<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>
这是我的GeneralTextInput.tsx我应该给输入什么作为参考,我应该如何关注它?
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>
);
};
尽量不要在 GeneralTextInput.tsx
中处理你的引用,在你的主文件中以不同的方式处理引用,并从主文件中传递 onSubmitEditing
属性。
为您的第二个 GeneralTextInput
创建一个 inputRef
并将其专注于您的第一个 GeneralTextInput
组件
<GeneralTextInput
onSubmitEditing = {() => inputRef.current.focus()}
...
>
<GeneralTextInput
ref = { inputRef }
...
>
然后只需将它们作为道具传递给您的 GeneralTextInput.tsx
文件。希望这对你有用
<TextInput
ref={props.ref || null}
onSubmitEditing={props.onSubmitEditing || null}
...
>
希望这对你有用。
如果我没理解错的话forwardRef就是你要找的。
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);
}
}}
/>
你用 forwardRef 包装 GeneralTextInput:
import { TextInput, TextInputProps } from "react-native";
export const GeneralTextInput: React.forwardRef<TextInput,IGeneralTextInputProps> = (
// type of props and ref will be inferred by ts
props
ref
) => {
....
return (
....
<TextInput
ref={ref}
{...props}
...
...
/>
)}
现在在父组件中定义一个useRef:
const secondInputRef = useRef<TextInput | null>(null);
您有 2 个通用输入。在第一次输入时
<GeneralTextInput
....
....
// add this. this will focus on secondInput
onSubmitEditing={() => {
secondInputRef.current?.focus();
}}
/>
第二个 GeneralInput 将保持原样
我在 React Native 中聚焦下一个输入时遇到问题。我在整个应用程序中只使用一个名为 GeneralTextInput.tsx 的输入。
在此示例中,我有 2 个输入 ==> 1.Group 名称, 2.Group 描述
所以我在父级中给这个组件一些道具:
<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>
这是我的GeneralTextInput.tsx我应该给输入什么作为参考,我应该如何关注它?
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>
);
};
尽量不要在 GeneralTextInput.tsx
中处理你的引用,在你的主文件中以不同的方式处理引用,并从主文件中传递 onSubmitEditing
属性。
为您的第二个 GeneralTextInput
创建一个 inputRef
并将其专注于您的第一个 GeneralTextInput
组件
<GeneralTextInput
onSubmitEditing = {() => inputRef.current.focus()}
...
>
<GeneralTextInput
ref = { inputRef }
...
>
然后只需将它们作为道具传递给您的 GeneralTextInput.tsx
文件。希望这对你有用
<TextInput
ref={props.ref || null}
onSubmitEditing={props.onSubmitEditing || null}
...
>
希望这对你有用。
如果我没理解错的话forwardRef就是你要找的。
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);
}
}}
/>
你用 forwardRef 包装 GeneralTextInput:
import { TextInput, TextInputProps } from "react-native";
export const GeneralTextInput: React.forwardRef<TextInput,IGeneralTextInputProps> = (
// type of props and ref will be inferred by ts
props
ref
) => {
....
return (
....
<TextInput
ref={ref}
{...props}
...
...
/>
)}
现在在父组件中定义一个useRef:
const secondInputRef = useRef<TextInput | null>(null);
您有 2 个通用输入。在第一次输入时
<GeneralTextInput
....
....
// add this. this will focus on secondInput
onSubmitEditing={() => {
secondInputRef.current?.focus();
}}
/>
第二个 GeneralInput 将保持原样