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

React Native自定义带标签TextInput点击Next无法聚焦问题解决

React Native自定义TextInput组件焦点切换失效问题解决

我之前开发了一个带标签的自定义TextInput组件,在页面里依次排列了全名、手机号、密码、PIN码四个该组件实例,但遇到了个麻烦:点击全名输入框的Next按键后,手机号输入框始终无法获取焦点。

原问题代码

自定义组件代码

export default function LabelledText(props) { 
  const [inputFocused, setFocused] = useState(props.focusInput); 
  const [inputValue, setValue] = useState(null); 

  if (props.focusInput && !inputFocused) { 
    console.log('label :: ' + props.label); 
    setFocused(props.focusInput); 
    this.labelledText.focus(); 
  } 

  return ( 
    <View> 
      <Text style={{ 
        color: inputFocused ? '#00a3ee' : Colors.LIGHT_BLACK_HEADING_TEXT, 
        fontSize: responsiveFontSize(1.4), 
        marginTop: responsiveHeight(2), 
        fontFamily: Font.regular, 
      }}> 
        {inputValue == null || inputValue.length == 0 ? inputFocused ? props.label : null : props.label} 
      </Text> 
      <View style={{flexDirection: 'row'}}> 
        <TextInput 
          ref={input => { this.labelledText = input; }} 
          showSoftInputOnFocus={true} 
          style={{ 
            width: '100%', 
            backgroundColor: 'transparent', 
            color: 'black', 
            marginVertical: 6, 
            fontFamily: Font.regular, 
            fontSize: responsiveFontSize(1.65), 
          }} 
          keyboardType={ props.keyboardType != undefined ? props.keyboardType : 'email-address' } 
          returnKeyType={ props.returnKeyType != undefined ? props.returnKeyType : 'next' } 
          placeholder={props.placeHolder} 
          value={inputValue} 
          onChange={data => { 
            console.log('b4' + data.nativeEvent.text); 
            props.onValueChange(data.nativeEvent.text); 
            setValue(data.nativeEvent.text); 
          }} 
          numberOfLines={1} 
          onFocus={() => { 
            LayoutAnimation.configureNext( LayoutAnimation.Presets.easeInEaseOut, ); 
            setFocused(true); 
          }} 
          onBlur={() => { setFocused(false); }} 
          onSubmitEditing={() => { props.onInputFinished(); }} 
          maxLength={props.maxLength} 
        /> 
      </View> 
      <View style={{ 
        width: '100%', 
        height: props.error ? 1.5 : inputFocused ? 1 : 0.5, 
        backgroundColor: props.error ? 'red' : inputFocused ? Colors.BLUE : Colors.LIGHT_BLACK_HEADING_TEXT, 
      }} /> 
      {props.error ? ( 
        <Text style={{ 
          color: 'red', 
          fontSize: responsiveFontSize(1.4), 
          marginTop: responsiveHeight(0.4), 
          fontFamily: Font.regular, 
        }}> 
          {props.errorText} 
        </Text> 
      ) : null} 
    </View> 
  ); 
}

父组件调用代码

<LabelledTextInput 
  placeHolder={'FULL NAME'} 
  label={'FULL NAME'} 
  returnKeyType={'next'} 
  keyboardType={'email-address'} 
  onValueChange={value => { 
    console.log(value); 
    const error_value = {...this.state.errors}; 
    delete error_value['fullname']; 
    this.setState({fullname: value, errors: error_value}); 
  }} 
  error={this.state.errors['fullname'] ? true : false} 
  errorText={this.state.errors['fullname']} 
  maxLength={20} 
  onInputFinished={() => { 
    this.setState({mobileEmailFocus: true}, () => { 
      console.log( 'user typing stopped and keyboard dismissed fullname' + this.state.mobileEmailFocus, ); 
    }); 
  }} 
/>

问题解决思路与修改方案

经过Vishnu的思路启发,我找到了问题所在并完成了修复,核心修改点如下:

  • 函数组件中正确使用Ref:原代码用this.labelledText存储Ref,但函数组件没有this,换成useRef Hook来管理TextInput的引用,确保能正确调用focus()方法。
  • 增加状态重置回调:添加removeStateFocus props回调,在触发焦点切换后重置相关状态,避免状态冲突导致焦点无法正常切换。
  • 修正焦点触发逻辑:当props.focusInput触发时,通过labelledText.current.focus()唤起输入框焦点,同时调用回调重置状态。

修改后的代码

自定义组件代码

export default function LabelledText(props) { 
  const [inputFocused, setFocused] = useState(props.focusInput); 
  const [inputValue, setValue] = useState(null); 
  const labelledText = useRef(null); 

  if (props.focusInput && !inputFocused) { 
    console.log('label :: ' + props.label); 
    setFocused(props.focusInput); 
    labelledText.current.focus(); 
    props.removeStateFocus(); 
  } 

  return ( 
    <View> 
      <Text style={{ 
        color: inputFocused ? '#00a3ee' : Colors.LIGHT_BLACK_HEADING_TEXT, 
        fontSize: responsiveFontSize(1.4), 
        marginTop: responsiveHeight(2), 
        fontFamily: Font.regular, 
      }}> 
        {inputValue == null || inputValue.length == 0 ? inputFocused ? props.label : null : props.label} 
      </Text> 
      <View style={{flexDirection: 'row'}}> 
        <TextInput 
          ref={labelledText} 
          showSoftInputOnFocus={true} 
          style={{ 
            width: '100%', 
            backgroundColor: 'transparent', 
            color: 'black', 
            marginVertical: 6, 
            fontFamily: Font.regular, 
            fontSize: responsiveFontSize(1.65), 
          }} 
          keyboardType={ props.keyboardType != undefined ? props.keyboardType : 'email-address' } 
          returnKeyType={ props.returnKeyType != undefined ? props.returnKeyType : 'next' } 
          placeholder={props.placeHolder} 
          value={inputValue} 
          onChange={data => { 
            console.log('b4' + data.nativeEvent.text); 
            props.onValueChange(data.nativeEvent.text); 
            setValue(data.nativeEvent.text); 
          }} 
          numberOfLines={1} 
          onFocus={() => { 
            LayoutAnimation.configureNext( LayoutAnimation.Presets.easeInEaseOut, ); 
            setFocused(true); 
          }} 
          onBlur={() => { setFocused(false); }} 
          onSubmitEditing={() => { props.onInputFinished(); }} 
          maxLength={props.maxLength} 
        /> 
      </View> 
      <View style={{ 
        width: '100%', 
        height: props.error ? 1.5 : inputFocused ? 1 : 0.5, 
        backgroundColor: props.error ? 'red' : inputFocused ? Colors.BLUE : Colors.LIGHT_BLACK_HEADING_TEXT, 
      }} /> 
      {props.error ? ( 
        <Text style={{ 
          color: 'red', 
          fontSize: responsiveFontSize(1.4), 
          marginTop: responsiveHeight(0.4), 
          fontFamily: Font.regular, 
        }}> 
          {props.errorText} 
        </Text> 
      ) : null} 
    </View> 
  ); 
}

父组件调用代码

<LabelledTextInput 
  placeHolder={'FULL NAME'} 
  label={'FULL NAME'} 
  returnKeyType={'next'} 
  keyboardType={'email-address'} 
  removeStateFocus={() => { 
    this.setState({mpinFocus: false}, () => { 
      console.log('remove focus fullname'); 
    }); 
  }} 
  onValueChange={value => { 
    console.log(value); 
    const error_value = {...this.state.errors}; 
    delete error_value['fullname']; 
    this.setState({fullname: value, errors: error_value}); 
  }} 
  error={this.state.errors['fullname'] ? true : false} 
  errorText={this.state.errors['fullname']} 
  maxLength={20} 
  onInputFinished={() => { 
    this.setState({mobileEmailFocus: true}, () => { 
      console.log( 'user typing stopped and keyboard dismissed fullname' + this.state.mobileEmailFocus, ); 
    }); 
  }} 
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 21:08:02