React Native中Formik/Yup数组验证无错误提示问题求助
问题修复方案
核心问题分析
- Formik初始值与任务列表不同步:原代码中Formik的
initialValues设为空数组,导致内部状态与API返回的任务列表脱节,验证无法绑定到对应字段。 - 错误/触摸状态访问方式错误:通过字符串拼接
${errors}${name}[${key}].comment获取状态的写法完全错误,Formik的errors和touched是嵌套对象/数组,需通过层级访问。 - 输入框值绑定错误:原代码用字符串索引取值的方式不符合Formik数组字段的访问规则。
修改后的完整代码
TaskScreen.js
import React from 'react'; import { StyleSheet, Button } from 'react-native'; import * as yup from 'yup'; import { Formik } from 'formik'; import { SubmitButton, Tasks } from "../components/forms"; // 支持开关状态的动态验证(仅关闭开关时需填写备注) const validationSchema = yup.object().shape({ tasks: yup.array().of( yup.object().shape({ isCompleted: yup.boolean(), comment: yup.string().when('isCompleted', { is: false, then: yup.string().required('未完成任务必须填写备注'), }) }) ), }); function TasksScreen({ navigation: { navigate }, route}) { // 将API返回的任务转换为带初始值的数组,匹配Formik验证结构 const initialTasks = route.params.tasks.map(task => ({ ...task, comment: '', isCompleted: false, // 默认关闭开关,用于测试验证 })); const handleSubmit = async (values) => { console.log('提交数据:', values); // 现在可正常打印Formik值 }; return ( <> <Formik initialValues={{ tasks: initialTasks }} onSubmit={handleSubmit} validationSchema={validationSchema} > <Tasks name="tasks" /> <SubmitButton title="提交" /> </Formik> <Button onPress={() => navigate('TaskLists') } title="返回"/> </> ) } const styles = StyleSheet.create({ container: {}, }); export default TasksScreen;
Tasks.js
import React from 'react'; import { useFormikContext, FieldArray } from "formik"; import ErrorMessage from "./ErrorMessage"; import { TextInput, Text, View, StyleSheet, Switch } from 'react-native'; function Tasks({ name }) { const { setFieldTouched, setFieldValue, errors, touched, values, } = useFormikContext(); // 直接从Formik状态中获取任务列表,无需外部传入 const tasks = values[name]; return ( <FieldArray name={name}> <> {tasks.map((task, key) => { const commentField = `${name}[${key}].comment`; const completedField = `${name}[${key}].isCompleted`; return ( <View key={key} style={styles.taskItem}> <Text>{task.name}</Text> {/* 开关组件,控制备注必填逻辑 */} <Switch value={task.isCompleted} onValueChange={(val) => setFieldValue(completedField, val)} onBlur={() => setFieldTouched(completedField)} /> <TextInput onBlur={() => setFieldTouched(commentField)} onChangeText={(text) => setFieldValue(commentField, text)} value={task.comment || ''} placeholder="请填写任务备注" style={styles.input} /> {/* 正确传递错误信息与触摸状态 */} <ErrorMessage error={errors?.[name]?.[key]?.comment} visible={touched?.[name]?.[key]?.comment} /> </View> ); })} </> </FieldArray> ); } const styles = StyleSheet.create({ taskItem: { marginVertical: 10, paddingHorizontal: 15, }, input: { borderWidth: 1, borderColor: '#ccc', borderRadius: 4, padding: 8, marginTop: 5, }, }); export default Tasks;
关键修复点说明
- 初始值同步:将API返回的任务转换为带
comment和isCompleted初始值的数组,确保Formik状态与业务数据匹配。 - 动态验证逻辑:使用Yup的
when方法实现开关状态关联的验证规则,仅当开关关闭时要求填写备注。 - 状态访问修正:通过
errors?.[name]?.[key]?.comment层级访问错误信息,避免字符串拼接的错误写法。 - 值绑定优化:直接从Formik的
values数组中取对应字段的值,确保输入框与状态双向同步。
内容的提问来源于stack exchange,提问作者Neval Mayer
相关产品推荐
相关产品推荐

