课程目标
本节课程将学习如何使用 Formik 提供的 Field
组件,将表单输入框和错误提示封装成一个通用的组件,以减少重复代码,并提升代码的复用性和可维护性。
1. 为什么要封装?
在上一节中,我们为每个输入框都绑定了 onChangeText
和 onBlur
事件,同时还手动显示错误提示信息。这些逻辑在多个输入框中重复出现。
通过封装一个通用的组件,我们可以:
- 减少重复代码
- 提升代码的复用性
- 提高代码的可读性和可维护性
2. 使用 Formik 的 Field 组件
Formik 提供了 Field
组件,它是一个高阶函数,封装了以下功能:
- 自动绑定
onChange
、onBlur
和value
等事件 - 提供
name
属性,用于指定字段名称 - 渲染自定义的组件
Field 的基本用法
以下是 Field
的基本用法:
<Field
name="account" // 表单字段的名称
component={Input} // 渲染的自定义组件
/>
<Field
name="password"
placeholder="请输入密码"
component={Input}
secureTextEntry
/>
3. 创建 Input 组件
3.1 创建组件文件
在 components/
目录下创建一个名为 Input.tsx
的文件。
3.2 Input 组件代码
以下是 Input 组件的完整代码:
import React from 'react';
import { View, Text, StyleSheet, TextInput, TextInputProps } from 'react-native';
import { FieldInputProps, FormikProps } from 'formik';
// 定义组件的 Props 类型
interface IProps extends TextInputProps {
field: FieldInputProps<any>; // Formik 提供的字段属性
form: FormikProps<any>; // Formik 提供的表单属性
}
class Input extends React.PureComponent<IProps> {
// 自定义 onChangeText 方法
onChangeText = (value: string) => {
const { form, field, onChangeText } = this.props;
console.log('---field', field.name);
// 调用 Formik 提供的 handleChange 方法
form.handleChange(field.name)(value);
// 调用父组件传递的 onChangeText 方法(如果存在)
if (onChangeText) {
onChangeText(value);
}
};
render() {
const { form, field, ...rest } = this.props; // 解构 Props
return (
<View style={styles.container}>
{/* 输入框 */}
<TextInput
style={styles.input}
{...rest}
onChangeText={form.handleChange(field.name)} // 绑定 Formik 的 handleChange
onBlur={form.handleBlur(field.name)} // 绑定 Formik 的 handleBlur
/>
{/* 错误提示 */}
<View>
<Text style={styles.error}>{form.errors[field.name]}</Text>
</View>
</View>
);
}
}
// 样式
const styles = StyleSheet.create({
container: {
marginVertical: 10,
},
input: {
height: 40,
paddingHorizontal: 10,
borderColor: '#ccc',
borderBottomWidth: StyleSheet.hairlineWidth,
},
error: {
position: 'absolute',
color: 'red',
marginTop: 5,
marginLeft: 10,
fontSize: 12,
},
});
export default Input;
4. 在表单中使用封装的 Input 组件
4.1 替换 TextInput
将原来的 TextInput
替换为 Field
组件,并使用自定义的 Input
组件:
<Field
name="account"
placeholder="请输入账号"
component={Input}
/>
<Field
name="password"
placeholder="请输入密码"
component={Input}
secureTextEntry
/>
4.2 添加 placeholder
通过 Field
的 placeholder
属性,可以为输入框添加占位符。
5. 测试功能
-
启动模拟器,打开登录页面。
-
验证以下功能:
- 输入框绑定了正确的字段。
- 校验失败时,显示对应的错误提示。
-
确认封装后表单功能是否正常。
6. 登录成功后的返回操作
6.1 添加返回函数
在 utils
目录下创建一个返回函数:
function goBack() {
if (navigationRef.current) {
navigationRef.current.goBack();
}
}
export { goBack };
6.2 在登录逻辑中调用返回函数
在 login.tsx
文件中,调用 goBack
方法:
onSubmit = (values: Values) => {
const { dispatch } = this.props;
dispatch({
type: 'login/login',
payload: values,
callback: () => {
goBack(); // 登录成功后返回上一页
},
});
};
7. 小结
7.1 本节内容总结
- 封装了通用的
Input
组件,减少重复代码。 - 使用 Formik 的
Field
组件,实现了事件绑定和错误提示的自动化处理。 - 实现了登录成功后的返回操作。
7.2 思想总结
本节重点在于封装的思想:
- 将重复的逻辑抽象为通用组件。
- 提升代码的复用性和可维护性。
虽然目前的表单较为简单,但在复杂表单中,这种封装方式可以显著减少代码量,并提升开发效率。
8. 下一节预告
在下一节中,我们将学习如何将登录信息保存到本地存储中,以便用户下次打开应用时能够记住登录状态。