使用 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 将保持原样