Клавиатура закрывается при вводе TextInput во вложенном функциональном компоненте React Native - PullRequest
2 голосов
/ 24 января 2020

У меня странная проблема: клавиатура продолжает закрываться во время набора текста, когда 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};

Все работает нормально, если я вставляю все напрямую в метод визуализации.

1 Ответ

2 голосов
/ 04 февраля 2020

ваша SignInForm функция (которая обрабатывается как компонент React, потому что ее заглавная и называется JSX) объявлена ​​внутри вашего SignInScreenC компонента. Это означает, что каждый рендер создает новый тип компонента React.

  1. SignInScreenC выполняет рендеринг в первый раз: создает SignInForm компонент, создает его экземпляр и отображает его
  2. SignInScreenC рендерит второй раз: создает другой, совершенно другой SignInForm компонент, создает его снова, эффективно размонтирует старый SignInForm и отображает новый SignInForm на своем месте
  3. поскольку старый ввод отключен, вы теряете фокус клавиатуры

Это происходит из-за того, как React обрабатывает рендеринг: всякий раз, когда встречается другой тип элемента, который должен отображаться вместо старого элемента, старого будет размонтирован. Чтобы реагировать, каждый новый SignInForm отличается от предыдущего, так как вы постоянно создаете новые функции

Решения:

  1. создайте отдельный SignInForm компонент вне SignInScreenC и передать все необходимые данные как реквизиты
  2. или вместо const SignInForm = () => return (...) использовать const renderSignInForm = () => return (...), а при рендеринге вместо <SignInForm/> назвать их как {renderSignInForm()}. Таким образом, он не будет рассматриваться как компонент и не подлежит размонтированию
...