在本节中,我们完成了账号模块的功能,以下是登录页面的实现:
一、创建登录页面组件
-
创建
Login组件在
pages文件夹下创建Login文件夹,并添加index.tsx文件:import React from 'react'; import { View, Text, ScrollView, StyleSheet } from 'react-native'; import { Formik } from 'formik'; import * as Yup from 'yup'; import CustomInput from './CustomInput'; import { connect, ConnectedProps } from 'react-redux'; import { RootState } from '@/models/index'; import { TouchableOpacity } from 'react-native'; const validationSchema = Yup.object().shape({ username: Yup.string().required('账号不能为空'), password: Yup.string().required('密码不能为空'), }); interface IProps extends ConnectedProps<typeof connector> {} class Login extends React.PureComponent<IProps> { handleSubmit = (values: { username: string; password: string }) => { const { dispatch } = this.props; dispatch({ type: 'user/login', payload: values, }); }; render() { return ( <ScrollView keyboardShouldPersistTaps="handled" style={styles.container}> <Text style={styles.logo}>听书</Text> <Formik initialValues={{ username: '', password: '' }} validationSchema={validationSchema} onSubmit={this.handleSubmit} > {({ handleChange, handleBlur, handleSubmit, values, errors, touched, }) => ( <> <CustomInput placeholder="请输入账号" value={values.username} onChangeText={handleChange('username')} onBlur={handleBlur('username')} error={errors.username} touched={touched.username} /> <CustomInput placeholder="请输入密码" value={values.password} onChangeText={handleChange('password')} onBlur={handleBlur('password')} error={errors.password} touched={touched.password} secureTextEntry /> <TouchableOpacity style={styles.loginButton} onPress={handleSubmit} > <Text style={styles.loginButtonText}>登录</Text> </TouchableOpacity> </> )} </Formik> </ScrollView> ); } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', padding: 20, paddingBottom: 200, }, logo: { color: '#ff4000', fontWeight: 'bold', fontSize: 50, textAlign: 'center', marginTop: 40, }, loginButton: { backgroundColor: '#007bff', padding: 10, borderRadius: 5, marginTop: 20, }, loginButtonText: { color: '#fff', }, }); const mapStateToProps = (state: RootState) => ({ user: state.user, }); const connector = connect(mapStateToProps); export default connector(Login); -
创建自定义输入控件
在
pages/Login文件夹中添加CustomInput.tsx文件:import React from 'react'; import { View, TextInput, Text, StyleSheet } from 'react-native'; interface IProps { placeholder: string; value: string; onChangeText: (text: string) => void; onBlur: () => void; error?: string; touched?: boolean; secureTextEntry?: boolean; } const CustomInput = (props: IProps) => { return ( <View style={styles.container}> <TextInput style={styles.input} placeholder={props.placeholder} value={props.value} onChangeText={props.onChangeText} onBlur={props.onBlur} secureTextEntry={props.secureTextEntry} /> {props.touched && props.error && ( <Text style={styles.errorText}>{props.error}</Text> )} </View> ); }; const styles = StyleSheet.create({ container: { marginBottom: 20, }, input: { borderWidth: 1, borderColor: '#ccc', padding: 10, borderRadius: 5, width: '100%', }, errorText: { color: 'red', fontSize: 12, paddingHorizontal: 5, }, }); export default CustomInput; -
更新导航器
在
navigator文件夹中更新ModalStackScreen:<ModalStack.Screen name="Login" component={Login} options={{ headerTitle: '登录', }} />;
二、更新账号页面组件
-
创建
Account组件在
pages文件夹下创建Account文件夹,并添加index.tsx文件:import React from 'react'; import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native'; import { connect, ConnectedProps } from 'react-redux'; import { RootState } from '@/models/index'; import defaultAvatar from '@/assets/images/default_avatar.png'; interface IProps extends ConnectedProps<typeof connector> {} class Account extends React.PureComponent<IProps> { goLogin = () => { const { navigation } = this.props; navigation.navigate('Login'); }; render() { const { user, isLoading } = this.props; return ( <View style={styles.container}> <View style={styles.loginView}> <Image source={defaultAvatar} style={styles.image} /> <View style={styles.right}> <TouchableOpacity onPress={this.goLogin} style={styles.loginButton}> <Text style={styles.loginButtonText}>立即登录</Text> </TouchableOpacity> <Text style={styles.tip}>登录后自动同步所有记录哦~</Text> </View> </View> </View> ); } } const mapStateToProps = (state: RootState) => ({ user: state.user.user, isLoading: state.user.isLoading, }); const connector = connect(mapStateToProps); const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', padding: 15, }, loginView: { flexDirection: 'row', alignItems: 'center', margin: 15, }, right: { marginLeft: 15, justifyContent: 'center', }, image: { width: 70, height: 70, borderRadius: 35, }, loginButton: { justifyContent: 'center', alignItems: 'center', height: 26, width: 76, borderRadius: 13, borderColor: '#f86442', borderWidth: 1, marginBottom: 7, }, loginButtonText: { color: '#f86442', fontWeight: '900', }, tip: { color: '#666', fontSize: 12, }, }); export default connector(Account);
三、总结
在本节中,我们创建了登录页面组件,并实现了账号页面的基本 UI 和跳转功能。通过使用 Formik 和 yup,我们实现了表单数据的管理和校验。下一节,我们将实现登录功能的逻辑和状态管理。