5

我有这个奇怪的问题,当 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};

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

4

2 回答 2

14

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

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

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

解决方案:

  1. 在外部创建单独SignInForm的组件SignInScreenC并将所有必要的数据作为道具传递
  2. 或者,而不是const SignInForm = () => return (...)use const renderSignInForm = () => return (...),并且在渲染时,而不是<SignInForm/>{renderSignInForm()}. 这样它就不会被视为一个组件,也不会成为卸载的对象
于 2020-02-03T22:49:46.960 回答
0

我在尝试将文本更改传播到父组件(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-11-07T01:30:27.297 回答