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

React Native 动态生成TextInput如何实现动态ref绑定与聚焦控制

React Native 动态数量验证码输入框适配方案

原代码核心问题

  • 违反React Hook使用规则:useRef 不允许在普通函数、循环、条件分支中调用,必须放在组件顶层执行
  • 硬编码了4个ref实例,无法适配自定义输入框长度的需求
  • 输入跳转、退格回跳、提交逻辑全部写死适配4个输入框场景,长度变化后直接访问不存在的ref导致崩溃
  • 验证码状态pin用普通变量存储,组件重渲染时会被重置,状态无法持久

修正后完整代码

import React, { useRef, useState, useEffect } from 'react'
import { TextInputProps, View, TextInput } from 'react-native'

interface iPinCode extends TextInputProps {
  onComplete: (code: string) => void
  length?: number
}

const PinCode: React.FunctionComponent<iPinCode> = ({ onComplete, length = 4 }) => {
  // 输入框样式
  const inputStyle = {
    height: 75,
    width: 50,
    fontSize: 26,
    color: '#FFF',
    backgroundColor: '#4B4B4B',
    borderRadius: 15,
    padding: 8,
    margin: 4,
  }

  // 存储所有输入框ref的数组
  const inputRefs = useRef<(TextInput | null)[]>([])
  // 存储验证码状态
  const [pin, setPin] = useState<string[]>(new Array(length).fill(''))

  // 长度变化时重置ref数组和验证码状态
  useEffect(() => {
    inputRefs.current = inputRefs.current.slice(0, length)
    setPin(new Array(length).fill(''))
  }, [length])

  // 生成输入框
  const renderInputs = () => {
    const inputs: JSX.Element[] = []
    for (let i = 0; i < length; i++) {      
      inputs.push(
        <TextInput
          key={i}
          style={[inputStyle, { textAlign: 'center' }]}
          onChangeText={text => {
            const newPin = [...pin]
            newPin[i] = text.slice(0, 1)
            setPin(newPin)

            // 输入内容后自动跳转到下一个输入框
            if (text.length > 0 && i < length - 1) {
              inputRefs.current[i + 1]?.focus()
            }
            // 全部输入完成触发回调
            if (newPin.every(val => val.length === 1)) {
              onComplete(newPin.join(''))
            }
          }}
          value={pin[i]}
          onKeyPress={({ nativeEvent }) => {
            // 退格时跳转到上一个输入框
            if (nativeEvent.key === 'Backspace' && i > 0 && pin[i].length === 0) {
              inputRefs.current[i - 1]?.focus()
            }
          }}
          secureTextEntry
          keyboardType="numeric"
          maxLength={1}
          returnKeyType={i === length - 1 ? 'done' : 'next'}
          onSubmitEditing={() => {
            const code = pin.join('')
            onComplete(code)
            console.log('PIN TO SEND: ', code)
          }}
          ref={el => inputRefs.current[i] = el}
          autoFocus={i === 0}
        />
      )
    }

    return (
      <View style={{ flexDirection: 'row', justifyContent: 'center' }}>
        {inputs}
      </View>
    )
  }

  return <>{renderInputs()}</>
}

export default PinCode

核心改动说明

  • 将ref存储改为数组结构,通过回调ref的方式动态绑定每个输入框实例,适配任意长度的输入框数量
  • 验证码状态用useState存储,保证组件重渲染时状态不会丢失
  • 所有跳转逻辑改为通用判断,通过当前输入框下标i和总长度length判断是否需要跳转、跳转目标位置
  • 增加可选链?.调用ref方法,避免ref未初始化时报错
  • 增加length变化的监听逻辑,自定义长度变化时自动重置状态和ref数组

内容的提问来源于stack exchange,提问作者user418385

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 08:45:05