React Native Formik / Yup Array Validation throws no errors

Viewed 80

i was trying for 3 days now to get array validation working with Formik and Yup in React Native with a FieldArray. The Validation was working but i can't get it how to display the errors.

I have many tasks from the api where the user needs to write a comment if the switch is false, for testing purposes i disabled the switch to find out how to get the array validation running.

The TaskScreen:

import React, { useState } 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({comment: yup.string().required('Required'),})),
});

function TasksScreen({ navigation: { navigate }, route}) {

  const [tasks, setTasks] = useState(route.params.tasks);
  const handleSubmit = async (values) => {
    console.log(values);  
  };
  
  return  (
    <>
      <Formik
          initialValues={{ tasks:  [] }}
          onSubmit={handleSubmit}
          validationSchema={validationSchema}
      >
          <Tasks name="tasks" tasks={tasks} />
          <SubmitButton title="Send" />
      </Formik>
      <Button onPress={() => navigate('TaskLists') } title="Back"/>
    </>
  )

}

const styles = StyleSheet.create({
  container: {},
});

export default TasksScreen;

The Tasks Component

import React from 'react';
import { useFormikContext, FieldArray } from "formik";
import ErrorMessage from "./ErrorMessage";
import { TextInput, Text, View, StyleSheet, Switch } from 'react-native';

function Tasks({ tasks, name }) {

const {
  setFieldTouched,
  setFieldValue,
  errors,
  touched,
  values,
} = useFormikContext();

return (

    <FieldArray name={name}>
      <>
        { tasks.map((task, key)=>{
          return (
              <>
            <View key={key}>
              <Text>{task.name} {`${name}[${key}].comment]`}</Text>
              <TextInput
                  onBlur={() => setFieldTouched(`${name}[${key}].comment`)}
                  onChangeText={(text) => setFieldValue(`${name}[${key}].comment`, text)}
                  value={values[`${name}[${key}].comment`]}
                  name={`${name}[${key}].comment`}
                  placeholder="Task comment please"
                />
              <ErrorMessage error={`${errors}${name}[${key}].comment`} visible={`${touched}${name}[${key}].comment`} />
            </View>
            </>
          )
        })}
    </>
  </FieldArray> 
);
}

const styles = StyleSheet.create({
container: {},
});

export default Tasks;

I also have problems to console.log the Formik Bag, can't figure it out, it's my first steps with RN, sorry if the question is boring.

Thanks in advance for any kind of help.

1 Answers

As mentioned here in the validation docs you should create a callback as a child of the Formik component which has an object combined with two params which are errors and touched: the errors are the validation errors of the forms and the touched is map of field names to **whether** the field has been touched. See this Sample provide by the Formik Docs.

     import React from 'react';
 import { Formik, Form, Field } from 'formik';
 import * as Yup from 'yup';
 
 const SignupSchema = Yup.object().shape({
   firstName: Yup.string()
     .min(2, 'Too Short!')
     .max(50, 'Too Long!')
     .required('Required'),
   lastName: Yup.string()
     .min(2, 'Too Short!')
     .max(50, 'Too Long!')
     .required('Required'),
   email: Yup.string().email('Invalid email').required('Required'),
 });
 
 export const ValidationSchemaExample = () => (
   <div>
     <h1>Signup</h1>
     <Formik
       initialValues={{
         firstName: '',
         lastName: '',
         email: '',
       }}
       validationSchema={SignupSchema}
       onSubmit={values => {
         // same shape as initial values
         console.log(values);
       }}
     >
       {({ errors, touched }) => (
         <Form>
           <Field name="firstName" />
           {errors.firstName && touched.firstName ? (
             <div>{errors.firstName}</div>
           ) : null}
           <Field name="lastName" />
           {errors.lastName && touched.lastName ? (
             <div>{errors.lastName}</div>
           ) : null}
           <Field name="email" type="email" />
           {errors.email && touched.email ? <div>{errors.email}</div> : null}
           <button type="submit">Submit</button>
         </Form>
       )}
     </Formik>
   </div>
 );
Related