You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Formik/Yup数组验证无错误提示问题求助

问题修复方案

核心问题分析

  1. Formik初始值与任务列表不同步:原代码中Formik的initialValues设为空数组,导致内部状态与API返回的任务列表脱节,验证无法绑定到对应字段。
  2. 错误/触摸状态访问方式错误:通过字符串拼接${errors}${name}[${key}].comment获取状态的写法完全错误,Formik的errors和touched是嵌套对象/数组,需通过层级访问。
  3. 输入框值绑定错误:原代码用字符串索引取值的方式不符合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;

关键修复点说明

  1. 初始值同步:将API返回的任务转换为带comment和isCompleted初始值的数组,确保Formik状态与业务数据匹配。
  2. 动态验证逻辑:使用Yup的when方法实现开关状态关联的验证规则,仅当开关关闭时要求填写备注。
  3. 状态访问修正:通过errors?.[name]?.[key]?.comment层级访问错误信息,避免字符串拼接的错误写法。
  4. 值绑定优化:直接从Formik的values数组中取对应字段的值,确保输入框与状态双向同步。

内容的提问来源于stack exchange,提问作者Neval Mayer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 11:15:43