【问题标题】:Keyboard dismisses while typing TextInput in nested functional component React Native在嵌套功能组件 React Native 中键入 TextInput 时键盘消失
【发布时间】:2020-01-24 07:19:10
【问题描述】:

我有一个奇怪的问题,当 TextInput 被放置在子功能组件中时,键盘在输入时一直关闭。如果 TextInput 直接放在父组件下,则不存在此问题。这是我的代码

const SignInScreenC = props => {

// define Hook states here    
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isEmailEmpty,setIsEmailEmpty] = useState(false);
const [isEmailValid,setIsEmailValid] = useState(true);
const [isPasswordEmpty,setIsPasswordEmpty] = useState(false);


/**
 * Called when Sign in is clicked.
 * checks if the form is valid
 */
 const _OnSignInClicked = () => {
   if(_isFormValid()) {
    //make api call
   }
 }

/* Checks if the form is valid
*/
const _isFormValid = () => {
   //reset values 
   setIsEmailEmpty(false);
   setIsEmailValid(true);
   setIsPasswordEmpty(false);

   let isValid = true;
   if(email.trim() === "") {
      setIsEmailEmpty(true);
      isValid = false;
    }
   else if(!AppUtils.isEmailValid(email)) {
      setIsEmailValid(false);
      isValid = false;
   }
   else if(password.trim() === "") {
      setIsPasswordEmpty(true);
      isValid = false;
   }
 return isValid;
}


const SignInForm = () => {
  return (

    <View style={styles.formStyle}>
    <TextInput
       key="email"
       label={Strings.hint_email}
       value={email}
       keyboardType="email-address"                            
       onChangeText={(text)=>  {
           setEmail(text)
           setIsEmailEmpty(false)
           setIsEmailValid(true)
       }}
       style={styles.marginStyle}
       autoCompleteType = "off"
       scrollEnabled = {false}
       autoCorrect={false}
       autoCapitalize={false}/>

       <TextInput
        key="pass"
        value={password}
        secureTextEntry ={true}
        label={Strings.hint_password}
        style={[styles.marginStyle,styles.stylePassword]}
        onChangeText={(text)=> {
             setPassword(text)
             setIsPasswordEmpty(false)}
        }
        theme="light"
        autoCompleteType = "off"
        scrollEnabled = {false}
        autoCorrect={false}
        autoCapitalize={false}/>
        <Button 
            style={styles.loginStyle}
            title = {Strings.login}
            onPressButton = {() => _OnSignInClicked()}/>

    </View>
  );
}

return ( 

    <>

        <ImageBackground source={Images.screen_backgound} style={{width: '100%', 
          height: '100%'}}>
            <View style = {styles.viewOverlaystyle} />
            <ScrollView  contentContainerStyle = {{flexGrow:1}} 
                keyboardShouldPersistTaps={'handled'}>
                <View style={styles.containerStyle}>
                    <SignInForm/>
                </View>
            </ScrollView>
        </ImageBackground>

    </>
 );
}

const styles = StyleSheet.create({
   ....
})

const mapStateToProps = state => ({
   userData : state.userData
});

const mapDispatchToProps = dispatch =>
    bindActionCreators(UserActions, dispatch);

 const SignInScreen = connect(mapStateToProps,mapDispatchToProps) (SignInScreenC)

 export {SignInScreen};

如果我将所有内容 直接粘贴到渲染方法,一切正常。

【问题讨论】:

  • 您如何在此处使用作为子组件的方式使用该代码更改您的问题。因此,我们可以找出您做错了什么。

标签: reactjs forms react-native nested react-native-textinput


【解决方案1】:

你的 SignInForm 函数(被视为 React 组件,因为它被大写并被称为 JSX)在你的 SignInScreenC 组件中声明。这意味着每次渲染,都会创建新的type React 组件。

  1. SignInScreenC 首次渲染:创建 SignInForm 组件,实例化并渲染它
  2. SignInScreenC 第二次渲染:创建另一个完全不同的 SignInForm 组件,再次实例化它,有效地卸载旧的SignInForm 并在其位置呈现新的SignInForm
  3. 由于旧输入被卸载,您失去了键盘焦点

这是由于 React 处理渲染的方式:当它遇到不同类型的元素应该被渲染来代替旧元素时,旧元素将被卸载。作为回应,每个新的SignInForm 都与之前的不同,因为您不断地创建新功能

解决方案:

  1. SignInScreenC 之外创建单独的SignInForm 组件并将所有必要的数据作为道具传递
  2. 或者,而不是 const SignInForm = () =&gt; return (...) 使用 const renderSignInForm = () =&gt; return (...),并且在渲染时,而不是 &lt;SignInForm/&gt; 将其称为 {renderSignInForm()}。这样,它就不会被视为组件,也不会成为卸载对象

【讨论】:

  • 完美解释。这就是我要找的。非常感谢:)
【解决方案2】:

我在尝试将文本更改传播到父组件(React Native)时遇到了一个略有不同但相关的问题。

如果您的组件冒泡 onChangeText 事件并触发重新渲染并随后失去对键盘的关注,您还可以考虑在用户完成输入文本并保持本地状态后传播您的更改事件 onEndEditing文本输入。

export function YourTextInputComponent(
  { initialValue, onChangeTextDone } : 
  { initialValue: string, onChangeTextDone : (text: string) => void) }
): JSX.Element {
  const [text, setText] = useState<string>(initialValue);
  
  return (
    <TextInput
      value={text}
      onChangeText={(txt) => {
        setText(txt);
      }}
      onEndEditing={(event) => {
        onChangeTextDone(text);
      }}
    />
  )
}
    

【讨论】:

    猜你喜欢
    • 2021-01-25
    • 1970-01-01
    • 2022-11-23
    • 2020-11-23
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 2018-01-31
    • 2020-09-13
    相关资源
    最近更新 更多