Formik error message

is a component that renders the error message of a given field if that field has been visited (i.e.touched[name] === true) (and there is an error message present). It expects that all error messages are stored for a given field as a string. Like , , and , lodash-like dot path and bracket syntax is supported.

<ErrorMessage /> is a component that renders the error message of a given field if that field has been visited (i.e.touched[name] === true) (and there is an error message present). It expects that all error messages are stored for a given field as a string. Like <Field />, <FastField />, and <FieldArray />, lodash-like dot path and bracket syntax is supported.

Example

import React from 'react';

import { Formik, Form, Field, ErrorMessage } from 'formik';

import * as Yup from "yup";

const SignupSchema = Yup.object().shape({

name: Yup.string()

.min(2, 'Too Short!')

.max(70, 'Too Long!')

.required('Required'),

email: Yup.string()

.email('Invalid email')

.required('Required'),

});

export const ValidationSchemaExample = () => (

<div>

<h1>Signup</h1>

<Formik

initialValues={{

name: '',

email: '',

}}

validationSchema={SignupSchema}

onSubmit={values => {

// same shape as initial values

console.log(values);

}}

>

{({ errors, touched }) => (

<Form>

<Field name="name" />

- {errors.name && touched.name ? (

- <div>{errors.name}</div>

- ) : null}

+ <ErrorMessage name="name" />

<Field name="email" type="email" />

- {errors.email && touched.email ? (

- <div>{errors.email}</div>

- ) : null}

+ <ErrorMessage name="email" />

<button type="submit">Submit</button>

</Form>

)}

</Formik>

</div>

);

Props


Reference

Props

children

children?: ((message: string) => React.ReactNode)

A function that returns a valid React element. Will only be called when the field has been touched and an error exists.

<ErrorMessage name="email">{msg => <div>{msg}</div>}</ErrorMessage>

component

component?: string | React.ComponentType<FieldProps>

Either a React component or the name of an HTML element to render. If not specified, <ErrorMessage> will just return a string.

<ErrorMessage component="div" name="email" />

<ErrorMessage component="span" name="email" />

<ErrorMessage component={Custom} name="email" />

<ErrorMessage name="email" />

name

name: string
Required

A field’s name in Formik state. To access nested objects or arrays, name can also accept lodash-like dot path like social.facebook or friends[0].firstName

render

render?: (error: string) => React.ReactNode

A function that returns a valid React element. Will only be called when the field has been touched and an error exists.

<ErrorMessage name="email" render={msg => <div>{msg}</div>} />

Subscribe to our newsletter

The latest Formik news, articles, and resources, sent to your inbox.

Copyright © 2020 Formium, Inc. All rights reserved.

id title

errormessage

<ErrorMessage />

<ErrorMessage /> is a component that renders the error message of a given field if that field has been visited (i.e.touched[name] === true) (and there is an error message present). It expects that all error messages are stored for a given field as a string. Like <Field />, <FastField />, and <FieldArray />, lodash-like dot path and bracket syntax is supported.

Example

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from "yup";

const SignupSchema = Yup.object().shape({
  name: Yup.string()
    .min(2, 'Too Short!')
    .max(70, 'Too Long!')
    .required('Required'),
  email: Yup.string()
    .email('Invalid email')
    .required('Required'),
});

export const ValidationSchemaExample = () => (
  <div>
    <h1>Signup</h1>
    <Formik
      initialValues={{
        name: '',
        email: '',
      }}
      validationSchema={SignupSchema}
      onSubmit={values => {
        // same shape as initial values
        console.log(values);
      }}
    >
      {({ errors, touched }) => (
        <Form>
          <Field name="name"  />
-           {errors.name && touched.name ? (
-            <div>{errors.name}</div>
-          ) : null}
+         <ErrorMessage name="name" />
          <Field name="email" type="email" />
-           {errors.email && touched.email ? (
-            <div>{errors.email}</div>
-          ) : null}
+         <ErrorMessage name="email" />
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  </div>
);

Props


Reference

Props

children

children?: ((message: string) => React.ReactNode)

A function that returns a valid React element. Will only be called when the field has been touched and an error exists.

// the render callback will only be called when the
// field has been touched and an error exists and subsequent updates.
<ErrorMessage name="email">{msg => <div>{msg}</div>}</ErrorMessage>

component

component?: string | React.ComponentType<FieldProps>

Either a React component or the name of an HTML element to render. If not specified, <ErrorMessage> will just return a string.

<ErrorMessage component="div" name="email" />
// --> {touched.email && error.email ? <div>{error.email}</div> : null}

<ErrorMessage component="span" name="email" />
// --> {touched.email && error.email ? <span>{error.email}</span> : null}

<ErrorMessage component={Custom} name="email" />
// --> {touched.email && error.email ? <Custom>{error.email}</Custom> : null}

<ErrorMessage name="email" />
// This will return a string. React 16+.
// --> {touched.email && error.email ? error.email : null}

name

name: string
Required

A field’s name in Formik state. To access nested objects or arrays, name can also accept lodash-like dot path like social.facebook or friends[0].firstName

render

render?: (error: string) => React.ReactNode

A function that returns a valid React element. Will only be called when the field has been touched and an error exists.

// the render callback will only be called when the
// field has been touched and an error exists and subsequent updates.
<ErrorMessage name="email" render={msg => <div>{msg}</div>} />

Introduction

Errors are a necessary part of all forms. Form requirements can range from very simple, to very complex. They range from simpler synchronous validations, to also including asynchronous validation. Formik has first class support for both synchronous and asynchronous validation. The basic form of this is the validate function. It can be a sync or async function.

Checking for Errors

The way that Formik handles errors is that the returned error structure should map an error message to same structure as your values. In our case we have a single level object with a firstName key. So if our value below is set like this, then our error should map accordingly.

{
  firstName: ''
}

{
  firstName: 'Erorr message',
}

It doesn’t matter how you check for errors in this function it just matters that the structure is returned, or if valid that an empty object is returned.

So here we check if firstName is empty and if it is we set an error message.

<Formik
  initialValues={{
    firstName: "",
  }}
  onSubmit={handleSubmit}
  validate={(values) => {
    let errors = {};
    if (!values.firstName) {
      errors.firstName = "Required";
    }
    return errors;
  }}
></Formik>

Controlling Error Rendering

Here we will control how an error gets rendered. The useField hook and Field both supply a meta object. The meta object is meta information about the specific field that’s being rendered.

So in our case it’s referencing meta information about our firstName field. A field might be in an erroneous state but we don’t want to bombard the user with the error message before they’ve even touched the field.

When a user interacts with a field, then triggers an onBlur the touched value is set to true. This allows us to now display an error message once we know it’s been touched and also that an error exists.

const MySpecialField = () => {
  const [field, meta] = useField("firstName");
  return (
    <div>
      <input {...field} className="border-2" />
      {meta.touched && meta.error && <div>{meta.error}</div>}
    </div>
  );
};

Formik Helper ErrorMessage

Generally the standard for displaying an error is that you need to have touched the field, and that an error exists. Formik ships with the ErrorMessage helper component.

import { ErrorMessage } from "formik";

You supply it with a name. When that fields contains an error and the field has been touched. Then it will display whatever the error text is. You can supply any component you’d like and it will pass the error text as a child.

<div>
  <Field name="firstName" className="border-2" />
  <ErrorMessage name="firstName" component="div" />
</div>

Submission

One thing to realize is that if the user submits all fields are set to the touched status. So even if the user didn’t trigger an onBlur on the firstName field. Then opted to click the Submit button, the error messages will pop up.

This is generally what you want but if this isn’t than you may need to handle how errors are displayed in your form and not use the ErrorMessage component.

Putting it all Together

import React from "react";
import { Formik, Form, Field, useField, ErrorMessage } from "formik";

const MySpecialField = () => {
  const [field, meta] = useField("firstName");
  return (
    <div>
      <input {...field} className="border-2" />
      {meta.touched && meta.error && <div>{meta.error}</div>}
    </div>
  );
};

function App() {
  const handleSubmit = (values) => {
    console.log(values);
  };

  return (
    <div className="App">
      <Formik
        initialValues={{
          firstName: "",
        }}
        onSubmit={handleSubmit}
        validate={(values) => {
          let errors = {};
          if (!values.firstName) {
            errors.firstName = "Required";
          }
          return errors;
        }}
      >
        {() => {
          return (
            <Form className="h-screen flex content-center flex-col justify-center">
              <div className="space-x-4 flex content-center justify-center">
                <div>
                  <Field name="firstName" className="border-2" />
                  <ErrorMessage name="firstName" component="div" />
                </div>
                <MySpecialField />
                <button
                  type="submit"
                  className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
                >
                  Submit
                </button>
              </div>
            </Form>
          );
        }}
      </Formik>
    </div>
  );
}

export default App;

Building forms with React involves setting up state as the container for user data and props as the means to control how state is updated using user input. Validation can be done in between user inputs, and an arbitrary submit function is executed on form submit.

Here is an example of a basic React form written without libraries and with minimal Bootstrap styling:

In the example below, we first initialize required state values in the constructor method. Since we have two required inputs — email and password — we initialize state for input values, input validity, and input errors:

constructor(props) {
  super(props);
  this.state = {
    formValues: {
      email: "",
      password: ""
    },
    formErrors: {
      email: "",
      password: ""
    },
    formValidity: {
      email: false,
      password: false
    },
    isSubmitting: false
  };
}

Next, we create the render method of the form with input values derived from state:

render() {
  const { formValues, formErrors, isSubmitting } = this.state;
  return (
    <div className="container">
      <div className="row mb-5">
        <div className="col-lg-12 text-center">
          <h1 className="mt-5">Login Form</h1>
        </div>
      </div>
      <div className="row">
        <div className="col-lg-12">
          <form onSubmit={this.handleSubmit}>
            <div className="form-group">
              <label>Email address</label>
              <input
                type="email"
                name="email"
                className={`form-control ${
                  formErrors.email ? "is-invalid" : ""
                }`}
                placeholder="Enter email"
                onChange={this.handleChange}
                value={formValues.email}
              />
              <div className="invalid-feedback">{formErrors.email}</div>
            </div>
            <div className="form-group">
              <label>Password</label>
              <input
                type="password"
                name="password"
                className={`form-control ${
                  formErrors.password ? "is-invalid" : ""
                }`}
                placeholder="Password"
                onChange={this.handleChange}
                value={formValues.password}
              />
              <div className="invalid-feedback">{formErrors.password}</div>
            </div>
            <button
              type="submit"
              className="btn btn-primary btn-block"
              disabled={isSubmitting}
            >
              {isSubmitting ? "Please wait..." : "Submit"}
            </button>
          </form>
        </div>
      </div>
    </div>
  );
}

Now we need to write the handleChange method to update the state with user inputs:

handleChange = ({ target }) => {
  const { formValues } = this.state;
  formValues[target.name] = target.value;
  this.setState({ formValues });
  this.handleValidation(target);
};

Anytime the state values are updated, we’ll run a validation method against user inputs. This is our handleValidation method:

handleValidation = target => {
  const { name, value } = target;
  const fieldValidationErrors = this.state.formErrors;
  const validity = this.state.formValidity;
  const isEmail = name === "email";
  const isPassword = name === "password";
  const emailTest = /^[^s@]+@[^s@]+.[^s@]{2,}$/i;
  validity[name] = value.length > 0;
  fieldValidationErrors[name] = validity[name]
    ? ""
    : `${name} is required and cannot be empty`;
  if (validity[name]) {
    if (isEmail) {
      validity[name] = emailTest.test(value);
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be a valid email address`;
    }
    if (isPassword) {
      validity[name] = value.length >= 3;
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be 3 characters minimum`;
    }
  }
  this.setState({
    formErrors: fieldValidationErrors,
    formValidity: validity
  });
};

The last part of this basic form is a handleSubmit method for the submission process. We need to check on formValidity values, and if there are any false values, run the validation method again without submitting the form.

handleSubmit = event => {
  event.preventDefault();
  this.setState({ isSubmitting: true });
  const { formValues, formValidity } = this.state;
  if (Object.values(formValidity).every(Boolean)) {
    alert("Form is validated! Submitting the form...");
    this.setState({ isSubmitting: false });
  } else {
    for (let key in formValues) {
      let target = {
        name: key,
        value: formValues[key]
      };
      this.handleValidation(target);
    }
    this.setState({ isSubmitting: false });
  }
};

Now the form is ready for use. React only provides the “view” layer for your application, and that means it provides only the basic necessities in making form components. component, state, and props are like puzzle blocks that you have to piece together to build a working form.

As you can see, it’s quite a lot of code for a form with only two text boxes. Imagine how many state values you need to keep track of in a form with 10 inputs or more. Yikes!

Yes, making forms with React is no fun; it’s very verbose and rigid. Building the form and creating validation method are boring tasks. In each form, you’d need to do the following, at a minimum:

  1. Set up state for form values, form errors, and form validity
  2. Handling user inputs and updating state
  3. Creating validation functions
  4. Handling submission

Building forms the natural “React” way requires you to write every part of the process from setting up states to form submission. I have done countless React forms, and I always find this part of building forms very boring and time-consuming. Fortunately, I’m not the only one feeling that way.

Enter Formik

Jared Palmer authored the Formik library out of frustration when building React forms. He needed a way to standardize the input components and the flow of form submission. Formik helps you to write the three most annoying parts of building a form:

  1. Getting values in and out of form state
  2. Validation and error messages
  3. Handling form submission

Here is the same form again, but this time using Formik:

This new form only uses four extra components from Formik library: <Formik />, <Form />, <Field />, and <ErrorMessage />. In order to unlock Formik’s power, you can wrap your form inside the <Formik /> component:

<Formik>
  <Form>
    {/* the rest of the code here */}
  </Form>
</Formik>

Let’s see how Formik makes building forms easier compared to React’s natural way.

Getting values in and out of form state

Formik will set up state internally for storing user inputs through its initialValues prop, so you don’t need to initialize state from constructor anymore.

In order to get values in and out of Formik internal state, you can use the <Field /> component to replace the regular HTML <input /> component. This component will do the magic of keeping Formik state and input value in sync, so you don’t have to pass value and onChange props into the <Field /> component:

<Formik
  initialValues={{ email: "", password: "" }}
  onSubmit={({ setSubmitting }) => {
    alert("Form is validated! Submitting the form...");
    setSubmitting(false);
  }}
>
  {() => (
    <Form>
      <div className="form-group">
        <label htmlFor="email">Email</label>
        <Field
          type="email"
          name="email"
          className="form-control"
        />
      </div>
      <div className="form-group">
        <label htmlFor="password">Password</label>
        <Field
          type="password"
          name="password"
          className="form-control"
        />
      </div>
    </Form>
  )}
</Formik>

With Formik, there’s no need to initialize state in constructor and create your own handleChange method anymore. It’s all taken care of.

Validation and error messages

Validation in Formik is executed automatically during specific events. All common events like after user input, on focus change, and on submit are covered, and you don’t have to worry about them. All you need to do is pass a function into Formik’s validate prop.

Compare this code between Formik validation and vanilla React validation:

// Formik validation code. Take values from Formik
validate={values => {
  let errors = {};
  if (values.email === "") {
    errors.email = "Email is required";
  } else if (!emailTest.test(values.email)) {
    errors.email = "Invalid email address format";
  }
  if (values.password === "") {
    errors.password = "Password is required";
  } else if (values.password.length < 3) {
    errors.password = "Password must be 3 characters at minimum";
  }
  return errors;
}}

// Vanilla React validation code. Take values given by handleChange
handleValidation = target => {
  const { name, value } = target;
  const fieldValidationErrors = this.state.formErrors;
  const validity = this.state.formValidity;
  const isEmail = name === "email";
  const isPassword = name === "password";
  const emailTest = /^[^s@]+@[^s@]+.[^s@]{2,}$/i;
  validity[name] = value.length > 0;
  fieldValidationErrors[name] = validity[name]
    ? ""
    : `${name} is required and cannot be empty`;
  if (validity[name]) {
    if (isEmail) {
      validity[name] = emailTest.test(value);
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be a valid email address`;
    }
    if (isPassword) {
      validity[name] = value.length >= 3;
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be 3 characters minimum`;
    }
  }
  this.setState({
    formErrors: fieldValidationErrors,
    formValidity: validity
  });
};

With validation in place, now you need to output error messages. Formik’s <ErrorMessage /> component will automatically display error message for the <Field /> component with the given name. You can adjust what HTML tag will be displayed through the component prop. Since this example form is using Bootstrap’s style, you will have to add a className prop as well:

// Formik error message output
<Field
  type="email"
  name="email"
  className={`form-control ${
    touched.email && errors.email ? "is-invalid" : ""
  }`}
/>
<ErrorMessage
  component="div"
  name="email"
  className="invalid-feedback"
/>

// Vanilla React error message output
<input
  type="email"
  name="email"
  className={`form-control ${
    formErrors.email ? "is-invalid" : ""
  }`}
  placeholder="Enter email"
  onChange={this.handleChange}
  value={formValues.email}
/>
<div className="invalid-feedback">{formErrors.email}</div>

The code for error message is actually about the same, but there’s a lot less code in Formik’s validation than in vanilla React. Way to go, Formik!

Even easier validation with Yup

Although you can already feel the benefit of using Formik in validation process, you can make it even easier by using an object schema validator.

An object schema validator is simply a library that allows you to define the blueprint of a JavaScript object and ensure that the object values match that blueprint through the validation process. This is particularly useful in validating form data since it’s actually an object kept inside Formik’s values prop.

Now one such library is Yup, and Formik’s author loves Yup so much that he included a special prop that connects Yup with Formik called validationSchema. This prop will automatically transform Yup’s validation errors into a pretty object whose keys match values and touched.

Here is an example of Formik using Yup as its validation schema. Notice how the validate prop is removed from the <Formik /> component:

With Yup’s object schema validator on place, you don’t have to manually write if conditions anymore. You can learn more about Yup and what kind of validation it can do by visiting its GitHub repo.

Form submission process

Formik’s <Form /> component will automatically run your validation method and cancel the submission process if there are any errors. While you have to include the onSubmit prop to a regular <form /> element, Formik’s <Form /> wrapper will run the onSubmit prop function you passed into the <Formik /> component:

// Formik's submit code. Won't be executed if there are any errors.
onSubmit={({ setSubmitting }) => {
  alert("Form is validated!");
  setSubmitting(false);
}}

// Vanilla React submit code. Check on validity state then run validation manually.
handleSubmit = event => {
  event.preventDefault();
  this.setState({ isSubmitting: true });
  const { formValues, formValidity } = this.state;
  if (Object.values(formValidity).every(Boolean)) {
    alert("Form is validated!");
    this.setState({ isSubmitting: false });
  } else {
    for (let key in formValues) {
      let target = {
        name: key,
        value: formValues[key]
      };
      this.handleValidation(target);
    }
    this.setState({ isSubmitting: false });
  }
};

Formik requires only four lines of code for submission at minimum, and you don’t need to keep track of the validity of form inputs. That’s pretty neat!

But what about redux-form?

Sure, redux-form works great, but then you’d need to use Redux in the first place. What if you’re using MobX? What if a new, better library comes up in the future and you want to replace Redux with that? On top of all that, does your React form actually affects the flow of your entire application in some way?

Think about it: Does the value of the username textbox somehow matter to your application globally? If not, then it’s really not necessary to track its value using Redux. Even the prophet Dan Abramov said the same thing.

Another problem with redux-form is that you are storing form input values into Redux store. This means your application will call on Redux’s reducer on every keystroke to update the value of just one textbox. Not a good idea.

I love writing forms the “Formik” way, but if you prefer redux-form, then that’s fine, too. 😉

Conclusion

Building forms is one of those things that React isn’t good at. Luckily, React has a community of developers that help each other and make the process of writing code easier.

Formik is definitely one of those open source libraries that’s a must-have if you are writing many forms in your React application. It really speeds up your development process and reduces boilerplate code by abstracting away parts of your form through components like <Field /> and <Form />.

While a vanilla React form requires you to specify your own state values and methods, you can simply pass props to the <Formik /> component to do the same things: handle user inputs, validate inputs, and form submission.

If you’d like to learn more about Formik, head over to the documentation or watch the presentation below by its creator.

React Distilled 2.0 is released

If you’d like to learn more about React and how you can use it to build a complete web application from scratch, I’m offering a 28% off my book React Distilled to celebrate its release (from $49 to $34). 

It includes new chapters on React Context API and React Hooks, and it shows how you can create React app using nothing but React and Firestore.

Go grab it now so you can be a React Genius today!

1_VEWXDp2iflV30wSyBBfEPA.png


Originally published at https://blog.logrocket.com on June 28, 2019.

I am making a web project using React, Material, Formik, formik-material-ui.

I have made a Formik form using yup for validation.

const schema = yup.object({
    name: yup.string().trim().lowercase().required("Name is required."),
});

<Formik
    initialValues={{
    name: "",
    }}
    validationSchema={schema}
>
    {({ submitForm, isSubmitting, handleSubmit, handleChange, values }) => (
        <Form noValidate onSubmit={handleSubmit}>
            <Grid container direction="row" spacing={2}>
                <Grid container item xs={12} spacing={4}>
                    <Grid item xs={4}>
                        <InputLabel>Patient Name *</InputLabel>
                        <TextField fullWidth name="name" type="text" />
                        <InputLabel>Patient ID: P0006</InputLabel>
                    </Grid>
                </Grid>
            </Grid>
        </Form>
    )}
</Formik>

The TextField is a custom component as follows

import React, { Fragment } from "react";
import { Field, ErrorMessage } from "formik";
import { TextField } from "libs/formik-material-ui/src";

const TextFieldStyle = {
    padding: 8,
    fontSize: "0.75rem",
};

export default React.memo((props: any) => {
    return (
        <Fragment>
            <Field
                component={TextField}
                inputProps={{
                    style: TextFieldStyle,
                }}
                size="small"
                margin="none"
                variant="outlined"
                {...props} // add props at the key to override any user defined similar props
            >
                {props.children}
            </Field>
            <ErrorMessage name={props.name}>{(msg) => <div style={{ color: "red", textAlign: "left" }}>{msg}</div>}</ErrorMessage>
        </Fragment>
    );
});

Since I want to display ErrorMessage of a different style and not the default one, I have added below the field.
But with this approach, the error message is being printed twice.

enter image description here

How can I disable the default message from being printed ?

Easy forms with Formik — part II

Follow me on Twitter, happy to take your suggestions on topics or improvements /Chris

This is the continuation of our first part on Formik, the amazing Forms library for React

This article is part of a series:

  • No more tears, handling Forms in React using Formik, part I
  • No more tears, handling Forms in React using Formik, part II, we are here

In this article we will cover:

  • Schema Validation with Yup, there is an alternate way to validate your input elements and that is by declaring a schema in Yup and simply assign that to an attribute on the Formik component
  • Async validation
  • Built-in components, make everything less verbose using some of Formiks built-in components

## Resources
I have made a repo for both these articles, so if you get stuck have a look here Form demo repo

Built-in components

So far we have been using regular HTML elements like form and input to build our form and we have connected to events like onSubmit, onChange and onBlur. But we can actually be typing a lot less. Say hello to the following components:

  • Form, this replaces a normal form element
  • Field, this replaces any type of input element
  • ErrorMessage, this doesn’t really replace any controls that you have but is a great component that given the attribute name is able to show your error message

Let’s first look at a simple form and then rewrite it using the above-mentioned components:

import { Formik } from 'formik';
import React from 'react';

const FormikExample = () => (
  <Formik
    initialValues={{ name: '' }}
    validation={values => {
      let errors = {};
      if(!values.name) {
        errors.name = 'Name is required';
      }
      return errors;
    }}
    onSubmit={values ={
      console.log('submitted');
    }}
  >
  {({ handleSubmit, handleChange, values, errors }) => (
   <form onSubmit={handleSubmit}>
    <input name="name" onChange={handleChange} value={values.name} />
    {errors.name && 
    <span>{errors.name}</span>
    }
   </form>
  )
  }
  </Formik>
)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Ok, above we see what a minimal implementation looks like the classical way of doing it, that is using HTML elements like form and input.

Now lets clean this up using Formiks built-in controls:

import { Formik, Form, Field, ErrorMessage } from 'formik';
import React from 'react';


const FormikExample = () => (
  <Formik
    initialValues={{ name: '' }}
    validation={values => {
      let errors = {};
      if(!values.name) {
        errors.name = 'Name is required';
      }
      return errors;
    }}
    onSubmit={values ={
      console.log('submitted');
    }}
  >
  {({ handleSubmit, errors }) => (
   <Form onSubmit={handleSubmit}>
    <Field type="text" name="name" />
    <ErrorMessage name="name"/>
    }
   </Form>
  )
  }
  </Formik>
)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Not super impressed? Let’s list what we don’t need to type anymore:

  • the onChange disappears from each input element
  • the input element is replaced by Field component
  • the form element is replaced by Form component
  • the conditional {errors.name && disappears as well as ErrorMessage component takes care of that bit

Not enough? Well imagine you have 10 fields, that is at least 10 lines of code that disappears and it generally it just looks cleaner. Now to our next improvement, we can replace our validation() function with a schema, up next.

Schema validation with Yup

Ok, we’ve covered how we can really clean up our markup by using the builtin controls Form, Field and ErrorMessage. Next step is improving even more by replacing our validation property with a validationSchema property. For that to be possible we need to define a schema using the library Yup. So what does a schema look like :

import * as Yup from 'yup'

const schema = 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'),
  });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

The above schema defines three different fields firstName, lastName and email and gives them each attributes that they should adhere to:

  • firstName, this should be a string consisting of min 2 characters and maximum 50 characters and its also required
  • lastName, this is also a string with the same min/max requirements and it’s also required
  • email, this is just a string that is required

As you can see the above is quite readable and by defining your data like this you save yourself from having to type a lot of if constructs checking if all attributes are fulfilled.

Let’s now put it to use in our Formik element, like so:

<Formik validationSchema={schema}>

1

That’s it, that is all you need to define your form data in a really expressive way, doesn’t that give you a warm and fuzzy feeling? 😃

Async validation

Ok, now to our last topic, asynchronous validation. So what’s the scenario? Well, sometimes you have data that you can’t really tell on client side only whether the entered value is correct or not. Imagine you have a form where you want to find out whether a company or certain web page domain is already taken? At that point, you most likely will need to make a call to an endpoint and the endpoint will not be coming back with the answer instantly.

Ok, we’ve set the scene, how do we solve this in Formik? Well, the validation property is able to accept a Promise as well. Really, you think? That easy? Well, the solution is in my mind a bit unorthodox, let me show you what I mean:

<Formik
  validate={values => {
    console.log('validating async');
    let errors = {};
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        errors.companyName = 'not cool';
        resolve('done');
      },3000);
      }).then(() => {
        if(Object.keys(errors).length) {
          throw errors;
        }
      });
    }}
>
// define the rest here
</Formik>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Looking at our validate implementation we see that we create a Promise that internally runs a setTimout to simulate it going to an endpoint that it takes time to get an answer from. At this point we set a errors.companyName to an error text:

setTimeout(() => {
  errors.companyName = 'not cool';
  resolve('done');
},3000);

1
2
3
4

In more real scenario we would probably call a function and depending on the functions answer we would possibly assign errors.companyName. I’ll show you below what I mean:

isCompanyNameUnique(values.companyName).then(isUnique => {
  if(!isUnique) {
    errors.companyName = `companyName is not unique, please select another one`
  }
  resolve('done')
})

1
2
3
4
5
6

Next thing that happens in our code is that we invoke then(), that happens when we call resolve(). Something really interesting happens in there, we check the errors for any properties that might have been set and if so we throw an error with our errors object as an argument, like so:

.then(() => {
  if(Object.keys(errors).length) {
    throw errors;
  }
});

1
2
3
4
5

I don’t know about you, but to me, this looks a bit weird. I would have thought providing validation with a Promise would have meant that a reject() of the Promise would have been a more intuitive way of doing it, like so:

// this to me would have been more intuitive, but observe, this is NOT how it works, so DONT copy this text but refer to the above code instead

validation={ values => 
  console.log('validating async');
  let errors = {};
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      errors.companyName = 'not cool';
      reject(errors);
    },3000);
  })
}}

1
2
3
4
5
6
7
8
9
10
11
12

Async on field level

So far we have shown how to do async validation on Forms level but if you think about would you really want that? Most likely you have a mix of fields where it’s enough to validate some of them client side while only a minority if fields need async validation. In such a case it makes sense to apply validation per field. That is quite easy to achieve by typing like this:

<Field name="username" validate={this.validate} >

1

This is probably preferred if you got async validation on a field. As for the other fields, you can validate client side it’s probably a good idea to define those in on the Formik components validationSchema and use Yup schemas for that as we’ve described above.

Words of caution

If we do have async validation in there make sure your validations don’t run too often especially if the validation takes time. You don’t want a 3-sec validation to trigger every time a key is typed, at most you want it when the user leaves the field to start typing in another field, we refer to this as the blur event. So make sure you set up your Formik component like this:

<Formik
  validateOnBlur={true} 
  validateOnChange={false} >

1
2
3

This does what you want, setting validateOnBlur to true is what you want, even though technically this is true by default. You want to be explicit with the next one though validateOnChange. You want this to be off, or set to false.

Summary

We’ve set out to cover built-in components like Form, Field and ErrorMessage, the end result was us cleaning up a lot of code.

Furthermore, we showed how we could get rid of our validation function by defining a schema using the Yup library.

Finally, we covered asynchronous validation and we discussed things to consider like when to validate and that it is probably best to have a field level validation for those few asynchronous fields that we have in a form and to use schema validation for the remaining fields.

That’s it, that was the end of our article. I hope this part and the previous one have given you new hope that dealing with Forms in React doesn’t have to that painful

This is Continuation to our previos article in which we have discussed about building Forms and Validating Forms in React using useFormik function. In this article, we will understand the Formik Component.

If we look at the code what we have written in our last session, though we have tried to make our code better by using getProps method, still we have to pass that to each input and we have to the code written for displaying the Validation Messages. To save us even more time and to make our code much better and easier, Formik comes with few built in components. They are <Formik />, <Form />, <Field />, and <ErrorMessage /><Formik/> is a component that helps us with building forms. Internally, Formik uses useFormik function to create the <Formik> component. useFormik() is a custom React hook that will return all Formik state and helpers directly. Despite its name, it is not meant for the majority of use cases.

Let’s now swap out the useFormik() hook for the Formik’s <Formik> component. Since it’s a component, we’ll convert the object passed to useFormik() to JSX, with each key becoming a prop. That means initialValues, validationSchema and onSubmit will be passed to this Formik Component as properties. Lets go to Index.js file from our demo project, in our EmployeeComponent’s return Method, Call a Component Called as Formik and to this Component, lets pass initialValues, validationSchema and onSubmit as properties. We will pass the same values we have used in useFormik function object.

return (

    <Formik initialValues= {{

      Id: '',

      Name: '',

      Location: '',

      Salary:'',

      EmailId:''

    }} validationSchema={yup.object({

      Name:yup.string().max(20,'Name should not exceed 20 Characters').

      required('Please Enter Employee Name'),

      Location: yup.string()

        .required('Please Enter Employee Location'),

      EmailId: yup.string()

        .email('Invalid email address')

        .required('Please Enter Email Id')

    })} onSubmit= {values => {

      alert(JSON.stringify(values));

    }}>

Lets add a div container and with in this Container, place a h2 tag with text as New Employee Form. Now lets call Form Component as Child Component from this Formik Component. Add a paragraph tag and place a label with Text as Employee ID. Now instead of placing an input, We will use another Component called as Field. To this field we will pass what type of input we want like text or number or email.

<p>

          <label htmlFor="Id">Employee ID </label>

          <Field name="Id" type="text"></Field>

</p>

Now lets repeat the same for Rest of the Form inputs like Name, Location, Salary and Email ID. Now We should display the Error messages when there is any Validation Error. In order to do this, we will use another Component called as ErrorMessage and specify property name for which the error should be displayed. We use an attribute called as name to specify the Property Name from our Formik values object. Now we will repeat the same for Location and Email ID as well. Lets save our changes, navigate to the browser. 

As we keep playing with the form inputs, respective validation messages are displayed. When we click on the button, we can see that forms data is displayed in an alert as a json object. Now if we look at the Code, Formik is the Parent Component and it has a nesting of Child Components. They are Form, Field and Error Message. Formik uses React Context internally to pass the data between these Components. 

We may think of using useFormik function if we don’t want to make use of React Context because we may want to use some other ways to share the data. In rest of the cases, it is recommended to use Formik Component. One must remember that We cant use Form, field, Error Message Components inside useFormik function. In our example we have used Field for generating the input elements. We can use Field Component to generate other html elements as well.

Now lets say we want to have a dropdownlist using which we can select the designation of the Employee. Lets add a new Property to our initialValues Object with a Name called Designation and initialize it to empty. Now with in our Form, add a new Field, assign the name as designation and to this field add a new attribute called as as and set the value as select. Add the respective options we want. For example, lets say we want to have Software Engineer, Senior Software Engineer and Lead as Designations.

Save these changes, navigate to the browser. Now we can see the dropdownlist available for us. Fill the form, click on the button. We can see the designation is added to our JSOn object as well.

Now lets say we want to disable the submit button if the form data is invalid. Formik Component has several Properties and we have used few properties like initialValues, validationSchema and onSubmit. Formik has another property called as isValid. IsValid Returns true if there are no errors  or if the errors Object is empty. And returns false if otherwise.

But in order to access any of the property from the Formik Component, we have to make a change. With in Formik Component, we will write an arrow function and properties of this formic component will be passed as a parameter to this function and this function will have our UI Code. Lets move all of our Form Code into this function.  Now to the button, add a new attribute called disabled and pass the isValid property. Now save these changes, navigate to the browser. We can see that button gets disabled when there are validation errors.

import React from 'react';

import ReactDOM from 'react-dom';

import { useFormik, Formik, Form, Field, ErrorMessage } from 'formik';

import * as yup from 'yup';



const EmployeeComponent =()=> {

  return (

    <Formik initialValues= {{

      Id: '',

      Name: '',

      Location: '',

      Salary:'',

      EmailId:'',

      Designation:''

    }} validationSchema={yup.object({

      Name:yup.string().max(20,'Name should not exceed 20 Characters').

      required('Please Enter Employee Name'),

      Location: yup.string()

        .required('Please Enter Employee Location'),

      EmailId: yup.string()

        .email('Invalid email address')

        .required('Please Enter Email Id')

    })} onSubmit= {values => {

      alert(JSON.stringify(values));

    }}>

      {props=>(

        <div>

    <h2>Enter Employee Details...</h2>

    <Form>

      <p>

          <label htmlFor="Id">Employee ID </label>

          <Field name="Id" type="text"></Field>

      </p>

      <p>

          <label htmlFor="Name">Employee Name </label>

          <Field name="Name" type="text"></Field>

          <ErrorMessage name="Name"></ErrorMessage>

      </p>

      <p>

          <label htmlFor="Location">Employee Location </label>

          <Field name="Location" type="text"></Field>

          <ErrorMessage name="Location"></ErrorMessage>

      </p>

      <p>

          <label htmlFor="Salary">Employee Salary </label>

          <Field name="Salary" type="text"></Field>

      </p>

      <p>

          <label htmlFor="EmailId">Employee Email ID </label>

          <Field name="EmailId" type="text"></Field>

          <ErrorMessage name="EmailId"></ErrorMessage>

      </p>

      <p>

        <label>Employee Designation : 

        <Field name="Designation" as="select">

  <option value="red">Software Engineer</option>

  <option value="green">Senior Software Engineer</option>

  <option value="blue">Lead</option>

</Field>

        </label>
      </p>
      <button type="submit" disabled={props.isValid==false}>Submit</button>

    </Form>

    </div>

      )}

    </Formik>
  );
}

const element=<EmployeeComponent></EmployeeComponent>

ReactDOM.render(element,document.getElementById("root"));

Video Reference


Понравилась статья? Поделить с друзьями:

Читайте также:

  • Formhack сервер недоступен как исправить
  • Former volume not mounted utorrent как исправить
  • Formatter silicon power error code 121
  • Formatter internal ram or rom error
  • Format is not supported or source is unavailable как исправить

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии