问题
I have this strange issue, keyboard keeps closing while typing when TextInput is placed inside Child Functional Component. This issue does not exist if TextInput is placed directly under Parent Component. Here is my code
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};
Everything works fine if I paste everything < SignInForm> directly to render method.
回答1:
your SignInForm function (which is treated like React component, because its capitalized and called as JSX) is declared inside your SignInScreenC component. This means that every render, new type of React component is created.
SignInScreenCrenders first time: createsSignInFormcomponent, instantiates it and renders itSignInScreenCrenders second time: creates another, completely differentSignInFormcomponent, instantiates it again, effectively unmounting oldSignInFormand rendering newSignInFormin it's place- since old input is unmounted, you lose keyboard focus
This is due to the way React handles rendering: whenever it encounters different type of element that should be rendered in place of an old element, old one will be unmounted. To react, every new SignInForm is different from the previous one as you keep constantly creating new functions
Solutions:
- create separate
SignInFormcomponent outside ofSignInScreenCand pass all the necessary data as props - or, instead of
const SignInForm = () => return (...)useconst renderSignInForm = () => return (...), and while rendering, instead of<SignInForm/>call it like{renderSignInForm()}. This way it will not be treated like a component and will not be a subject to unmounts
来源:https://stackoverflow.com/questions/59891992/keyboard-dismisses-while-typing-textinput-in-nested-functional-component-react-n