如何解决React Native:在输入TextInput
我有一个功能组件登录屏幕,其中有4个输入字段以及一个登录按钮。 这是组件屏幕的完整代码:
export default function Login() {
//Configs
const navigation = useNavigation();
const orientation = useDeviceOrientation();
const { colors,dark } = useTheme();
const InputTheme = {
colors: {
placeholder: colors.accent,primary: colors.accent,error: "red",},};
/** State Codes */
//States
const [login,setLogin] = useState({
email: "",password: "",licenseKey: "",deviceName: "",});
const [loading,setLoading] = useState(false);
const [secureEntry,setSecureEntry] = useState(true);
//Errors
const [errorEmail,setEmailError] = useState(false);
const [errorPWD,setPWDError] = useState(false);
const [errorLicense,setLicenseError] = useState(false);
const [errorDevice,setDeviceError] = useState(false);
//Error Messages
const [messageEmail,setEmailMessage] = useState("Looks Good");
const [messagePWD,setPWDMessage] = useState("All Good");
async function VerifyInputs() {
var pattern = /^[a-zA-Z0-9\-_]+(\.[a-zA-Z0-9\-_]+)*@[a-z0-9]+(\-[a-z0-9]+)*(\.[a-z0-9]+(\-[a-z0-9]+)*)*\.[a-z]{2,4}$/;
if (login.email == "") {
//Email cannot be empty
setEmailMessage("Email cannot be Blank!");
setEmailError(true);
return;
} else if (login.email != "" && !pattern.test(login.email)) {
//Email is not valid
setEmailMessage("This is not a valid email address!");
setEmailError(true);
return;
} else {
console.log("resolved email");
setEmailMessage("");
setEmailError(false);
}
if (login.password == "") {
//Password cannot be empty
setPWDMessage("Password cannot be Empty!");
setPWDError(true);
return;
} else if (login.password.length < 5) {
//Password must be minimum 5 characters.
setPWDMessage("Password must be of minimum 5 characters!");
setPWDError(true);
return;
} else {
console.log("resolved password");
setPWDMessage("");
setPWDError(false);
}
if (login.licenseKey == "") {
//License Key can't be Empty
setLicenseError(true);
return;
} else {
console.log("License resolved");
setLicenseError(false);
}
if (login.deviceName == "") {
//Device Name can't be empty as well
setDeviceError(true);
return;
} else {
console.log("Device name resolved");
setDeviceError(false);
}
Toast.show("Validation Successful");
}
function MobileContent() {
console.log("mobile_content rerendered");
return (
<View style={{ flex: 1,backgroundColor: colors.accent }}>
<View style={{ flex: 1,justifyContent: "center",alignItems: "center" }}></View>
<View style={{ flex: 3,justifyContent: "center" }}>
{/**Main Content */}
<View style={[styles.content,{ backgroundColor: colors.primary }]}>
<View style={{ flex: 1 }}>
{/**For Header */}
<Header />
</View>
<View style={{ flex: 5 }}>
{/**For Content */}
<ScrollView style={{ flex: 1 }}>
<LoginContent />
</ScrollView>
</View>
<View style={{ flex: 1 }}>
{/**For Footer */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function TabContent() {
console.log("tab_content rerendered");
return (
<View
style={{
flex: 1,backgroundColor: colors.accent,flexDirection: orientation.landscape ? "row" : "column",}}>
<View
style={{
flex: 1,alignItems: "center",}}></View>
<View style={{ flex: 1.5,{ backgroundColor: colors.primary }]}>
{/**Header Wrapper */}
<View style={{ justifyContent: "center" }}>
{/**Header Title */}
<Header />
</View>
{/**Content Wrapper */}
<LoginContent />
{/**Footer Wrapper */}
<View style={{ justifyContent: "center" }}>
{/** Login Button */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function Header() {
console.log("header_component rerendered");
return (
<View style={{ margin: "5%" }}>
<Title>Welcome User</Title>
<Subheading>Please Sign In to Continue..</Subheading>
</View>
);
}
function Footer() {
console.log("footer_component rerendered");
return (
<View style={{ margin: isTablet ? "5%" : "3.5%" }}>
<Button
title="Login"
loading={false}
ViewComponent={LinearGradient}
containerStyle={{ maxWidth: isTablet ? "45%" : "100%" }}
buttonStyle={{ height: 50,borderRadius: 10 }}
linearGradientProps={{
colors: [colors.accent,colors.accentLight],start: { x: 1,y: 1 },end: { x: 1,y: 0 },}}
onPress={() => {
VerifyInputs();
//navigation.navigate("verify");
}}
/>
</View>
);
}
function LoginContent() {
console.log("login_component rerendered");
return (
<View style={{ margin: "3%" }}>
{/**Login & Email Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Email"
value={login.email}
error={errorEmail}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login,email: text })}
/>
{errorEmail ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messageEmail}
</HelperText>
) : null}
</View>
<View style={styles.input}>
<View style={{ flexDirection: "row",alignItems: "center" }}>
<TextInput
mode="outlined"
label="Password"
value={login.password}
error={errorPWD}
theme={InputTheme}
secureTextEntry={secureEntry}
style={{ flex: 1,marginBottom: 5,marginEnd: isTablet ? 15 : 5 }}
onChangeText={(text) => setLogin({ ...login,password: text })}
/>
<Button
icon={
<Icon
name={secureEntry ? "eye-off-outline" : "eye-outline"}
size={30}
color={colors.primary}
/>
}
buttonStyle={{
width: 55,aspectRatio: 1,borderRadius: 10,}}
containerStyle={{ marginStart: 5 }}
onPress={async () => setSecureEntry(!secureEntry)}
/>
</View>
{errorPWD ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messagePWD}
</HelperText>
) : null}
</View>
</View>
{/**License & Device Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="License Key"
value={login.licenseKey}
error={errorLicense}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login,licenseKey: text })}
/>
{errorLicense ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
License Key cannot be Empty!
</HelperText>
) : null}
</View>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Device Name"
value={login.deviceName}
error={errorDevice}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login,deviceName: text })}
/>
{errorDevice ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
Device Name cannot be empty
</HelperText>
) : null}
</View>
</View>
</View>
);
}
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle={"dark-content"} backgroundColor={colors.accent} />
{isTablet ? <TabContent /> : <MobileContent />}
</SafeAreaView>
);
}
通过查看代码,您可以看到。.Login
组件基于电话或平板电脑的设备类型的渲染响应组件布局,以下组件MobileContent
或TabContent
。 / p>
MobileContent
功能组件将我的主要内容包装在ScrollView中,而TabContent
功能组件不需要滚动视图,但具有响应缩放视图。
这两个父组件都显示了我的公用组件Header
,LoginContent
和Footer
。
我的Header
组件仅显示标准标题和副标题。我的LoginContent
组件中还具有验证逻辑设置的所有TextInput字段。我的Footer
组件具有“提交/登录”按钮。就这些。
因此我们可以将屏幕的组件树总结为:
登录屏幕/父组件=>移动内容/标签内容=>页眉,LoginContent和页脚(通用组件)
好的,那么现在出了什么问题?对我来说,主要问题在于LoginContent
组件中的TextInputs,但我认为基本问题适用于整个“登录屏幕”组件。
问题::当我单击TextInput字段时,输入获得焦点并出现键盘。到目前为止,一切都很好。只要输入一个字母,就可以在键盘上按一下键。键盘立即关闭,文本输入失去焦点。
为什么会发生呢?我相信这可能是经典的“反应组件重新渲染”问题,当onChangeText
为TextInput更新状态时,它会导致TextInput重新渲染,从而失去焦点,这就是键盘关闭的原因
因此,我希望从这两个问题中至少解决第一个问题。
问题1:当我尝试在任何TextInput字段中键入内容时,如何防止键盘不断关闭。
问题2:如何使用这两个React Hooks useCallback()
和useMemo()
中的任何一个更好地优化每个状态更新时的Parent&Children组件渲染?
我已经多次阅读了这两个钩子useCallback
和useMemo
的文档,但仍然没有掌握这些钩子的概念。所有已发布的示例都处理了使用useCallback或useMemo优化的Counter Exmaple,但是我在屏幕上不使用Counters。
我需要在屏幕组件中更实用的示例useCallback()
和useMemo()
。在我当前的“登录屏幕”组件中实现这两个钩子也许可以帮助我更好地理解和理解该概念。
就像我提到的那样,解决问题1是我的最高优先级atm,但是从长远来看,我知道解决问题2的解决方案也会对我有帮助。如果您可以在此处解决我的两个问题,将非常有帮助。感谢您的帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。