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,换成useRefHook来管理TextInput的引用,确保能正确调用focus()方法。 - 增加状态重置回调:添加
removeStateFocusprops回调,在触发焦点切换后重置相关状态,避免状态冲突导致焦点无法正常切换。 - 修正焦点触发逻辑:当
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
相关产品推荐
相关产品推荐

