如何用React Hook Form实现React Native多屏表单提交与校验?
React Native 多屏表单实现方案(React Hook Form)
核心实现思路
- 借助React Hook Form的全局校验能力,结合React Navigation实现错误屏幕自动跳转
- 所有表单字段共享同一个
control实例,保证跨屏幕的数据与校验状态统一 - 提交时触发全量校验,根据错误字段定位并导航到对应屏幕
完整代码实现
1. 表单Hook封装(可单独存为useContractForm.ts)
import { useForm, yupResolver } from 'react-hook-form'; import * as yup from 'yup'; // 定义表单数据类型 type ContractFormData = { screen1Field: string; screen2Field: number; screen3Field: boolean; }; // Yup校验规则 const contractFormSchema = yup.object().shape({ screen1Field: yup.string().required('首屏字段必填'), screen2Field: yup.number().min(10, '第二屏字段不能小于10').required('第二屏字段必填'), screen3Field: yup.boolean().oneOf([true], '第三屏必须勾选'), }); export const useContractForm = () => { const { control, reset, handleSubmit, setValue, getValues, formState: { errors }, trigger, } = useForm<ContractFormData>({ resolver: yupResolver(contractFormSchema), mode: 'all', }); return { handleSubmit, getValues, setValue, control, errors, reset, trigger, }; };
2. 首屏组件(含提交按钮)
import React from 'react'; import { View, TextInput, Button, Text } from 'react-native'; import { Controller } from 'react-hook-form'; import { useContractForm } from './useContractForm'; import { useNavigation } from '@react-navigation/native'; const Screen1 = () => { const { control, errors, handleSubmit } = useContractForm(); const navigation = useNavigation(); // 最终提交逻辑 const onSubmit = (data: ContractFormData) => { console.log('提交的表单数据:', data); // 这里可添加API调用等业务逻辑 }; // 带错误跳转的提交处理 const handleFormSubmit = async () => { const isValid = await handleSubmit(onSubmit)(); if (!isValid) { // 根据错误字段导航到对应屏幕 if (errors.screen2Field) { navigation.navigate('Screen2'); } else if (errors.screen3Field) { navigation.navigate('Screen3'); } // 首屏字段错误则留在当前页展示 } }; return ( <View style={{ padding: 20 }}> <Controller control={control} name="screen1Field" render={({ field: { onChange, value } }) => ( <TextInput placeholder="首屏输入字段" value={value} onChangeText={onChange} style={{ borderWidth: 1, padding: 10, marginBottom: 10 }} /> )} /> {errors.screen1Field && ( <Text style={{ color: 'red', marginBottom: 20 }}>{errors.screen1Field.message}</Text> )} <Button title="提交表单" onPress={handleFormSubmit} /> </View> ); }; export default Screen1;
3. 第二屏组件
import React from 'react'; import { View, TextInput, Text } from 'react-native'; import { Controller } from 'react-hook-form'; import { useContractForm } from './useContractForm'; const Screen2 = () => { const { control, errors } = useContractForm(); return ( <View style={{ padding: 20 }}> <Controller control={control} name="screen2Field" render={({ field: { onChange, value } }) => ( <TextInput placeholder="第二屏数字字段" value={value?.toString() || ''} onChangeText={(text) => onChange(Number(text))} keyboardType="numeric" style={{ borderWidth: 1, padding: 10, marginBottom: 10 }} /> )} /> {errors.screen2Field && ( <Text style={{ color: 'red', marginBottom: 20 }}>{errors.screen2Field.message}</Text> )} </View> ); }; export default Screen2;
4. 第三屏组件
import React from 'react'; import { View, Switch, Text } from 'react-native'; import { Controller } from 'react-hook-form'; import { useContractForm } from './useContractForm'; const Screen3 = () => { const { control, errors } = useContractForm(); return ( <View style={{ padding: 20 }}> <Controller control={control} name="screen3Field" render={({ field: { onChange, value } }) => ( <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 10 }}> <Text>第三屏勾选框:</Text> <Switch value={value || false} onValueChange={onChange} /> </View> )} /> {errors.screen3Field && ( <Text style={{ color: 'red', marginBottom: 20 }}>{errors.screen3Field.message}</Text> )} </View> ); }; export default Screen3;
关键说明
- 所有屏幕共用同一个
useContractForm实例,确保数据和校验状态全局同步 - 提交时通过
handleSubmit触发全量校验,校验不通过时根据errors对象中的错误字段跳转对应屏幕 - 每个字段通过
Controller组件与React Hook Form绑定,同步输入值并触发校验规则 - 错误信息直接在对应屏幕的输入组件下方展示,用户修改后校验状态自动更新
内容的提问来源于stack exchange,提问作者Narek Hovhannisyan
相关产品推荐
相关产品推荐

