You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript下React Native使用useRef实现自定义TextInput聚焦下一个输入框

问题原因

你当前的实现错误点在于将输入框ref定义在了GeneralTextInput组件内部,每个GeneralTextInput实例的ref都是独立存储的,第一个输入框实例内部的groupDescRef根本无法指向第二个输入框的真实实例,所以调用focus方法无效。

修改步骤

1. 改造GeneralTextInput.tsx支持透传ref

首先使用React.forwardRef包裹自定义输入组件,将父组件传入的ref绑定到内部原生TextInput上,同时补充onSubmitEditing到props接口允许父组件自定义提交逻辑:

// 首先给IGeneralTextInputProps新增可选的onSubmitEditing属性
export interface IGeneralTextInputProps
    extends IStyledComponent<GeneralTextInputStyles> {
    // 原有所有属性保持不变,新增以下属性
    readonly onSubmitEditing?: () => void;
}

// 用forwardRef改造组件,泛型第一个参数是ref指向的原生TextInput类型,第二个是props类型
export const GeneralTextInput = React.forwardRef<TextInput, IGeneralTextInputProps>((props, ref) => {
    const classes = useStyles(props);
    const { fonts, colors } = useTheme();
    const [isPressed, setIsPressed] = React.useState(false);
    const [isPasswordVisible, setPasswordVisible] = React.useState(false);

    // 删掉原来组件内部定义的groupNameRef、groupDescRef,这两个ref跨实例无法访问没有作用

    return (
    <View style={classes.container}>
        <TouchableWithoutFeedback>
        <View style={classes.root}>
            <TextInput
            // 绑定父组件传入的ref
            ref={ref}
            // 优先执行父组件传入的提交逻辑
            onSubmitEditing={props.onSubmitEditing}
            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>
    );
});

2. 修改父组件代码控制跳转逻辑

父组件内创建两个ref分别对应两个输入框,把ref传入对应的GeneralTextInput,同时给第一个输入框配置提交时聚焦第二个输入框的逻辑:

// 父组件顶部先创建对应ref
const groupNameRef = React.useRef<TextInput>(null);
const groupDescRef = React.useRef<TextInput>(null);

// 渲染部分修改如下
<View style={classes.formContainer}>
  <Text style={classes.label}>{t("group.name-your-group")}</Text>

  <GeneralTextInput
    ref={groupNameRef}
    width={"100%"}
    returnKeyType={"next"}
    isDoneReference={false}
    deleteIcon
    startIcon={"account-multiple"}
    bordered={true}
    placeholder={t("form.placeholders.groupName")}
    value={props.newGroupName}
    // 新增提交逻辑:点击键盘下一步聚焦描述输入框
    onSubmitEditing={() => groupDescRef.current?.focus()}
    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
    ref={groupDescRef}
    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>
额外注意事项
  • 如果你使用的是React Native 0.65+版本,多行输入框设置returnKeyType为next/done时,需要额外设置blurOnSubmit={false}才会触发onSubmitEditing而不是直接换行,你当前第二个输入框是done类型,设置了blurOnSubmit={true}符合需求。
  • 不要在通用复用组件内部存储特定业务的ref,所有跨组件的ref访问都应该放在父业务层维护,保证复用组件的通用性。

内容的提问来源于stack exchange,提问作者Oğuzhan Yıldırım

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:06:04