【问题标题】:React Native Text Input focus with useRef using Typescript使用 Typescript 将本机文本输入焦点与 useRef 反应
【发布时间】:2021-11-17 15:58:26
【问题描述】:

我在关注 React Native 中的下一个输入时遇到问题。我在整个应用程序中只使用了一个名为 GeneralTextInput.tsx 的输入。

在这个例子中我有 2 个输入 ==> 1.Group Name, 2.Group Description

所以我在这个组件的父级中给了一些道具:

<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 我应该为输入提供什么作为 ref 以及我应该如何关注它?

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>
    );
};

【问题讨论】:

    标签: javascript reactjs typescript react-native react-native-textinput


    【解决方案1】:

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

    【讨论】:

    • adamsın hayat kurtardın :D
    【解决方案2】:

    如果我理解正确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);
            }
          }}
        />
    

    【讨论】:

      【解决方案3】:

      尽量不要在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}
          ...
      >
      

      希望这对你有用。

      【讨论】:

      • 嗨。谢谢回答。我现在这样尝试。我为两者添加了不同的独特参考。我通过了这样的道具:ref={null} onSubmitEditing={() => inputRef2.current?.focus()}。我将它们放在组件中,例如: ref={() => props.ref || null} onSubmitEditing={() => props.onSubmitEditing} 。但仍然无法正常工作:((
      • 按照我的方式进行操作,您不需要将 ref={null} 或任何 ref 属性传递给您关注的组件。我猜你的TextInput 组件中的ref={props.ref || null} 不是ref={() =&gt; props.ref || null} 之类的简单传递引用。记录您的 refonSubmitEditing 属性,确保在关注下一个输入字段时在 GeneralTextInput.tsx 中获得两者的值。
      猜你喜欢
      • 2020-04-28
      • 2019-04-16
      • 2017-02-06
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 2018-12-18
      • 2020-10-05
      相关资源
      最近更新 更多