Creating React forms with Formik-React.js

Formik is a compact group of react components and hooks. These are used to build forms in React and React Native. Getting values into the form and out of the form state, Validation error messages, form submission handling etc are some examples of the annoying tasks Formik takes care of. React.js makes development very much easier. Creating forms are also simple in React.js. When you need to have more than one form, using a simple controlled form becomes a cumbersome, redundant task. There are other libraries out there like Redux to make form handling easier but it can be excessive for simple apps because running each form through redux store will make the performance of your applications worse. Formik is now used for all these kinds of annoying tasks that are related to forms. It is becoming popular very fast. It utilizes the React render method concept. It doesn’t use any frameworks or complex coding. To install Formik and yup type the below command.


npm install formik
npm install yup--save
Install Yup with Formik using the yarn command as given below.
yarn add formik yup
Now we create an index.js page.

We have an ImaginaryUser variable in index.js. We assume an imaginary user entering email, username etc in our form. ImaginaryUser variable can come from wherever you want like API, from a file. We need default values to map into Formik. Now we create UserForm.js.

You can see how Formic, yup dependencies are rendered in this file. Here react-virtualized-select is used for select boxes. We have ImaginaryThings which we have used to view and select an array of options. You will get a simple form with an imaginary email, username and another field.



import React from 'react';

import { Formik } from 'formik';

import Yup from 'yup';

import VirtualizedSelect from 'react-virtualized-select';


import 'react-select/dist/react-select.css';

import 'react-virtualized/styles.css';

import 'react-virtualized-select/styles.css';


const imaginaryThings = [

  { label: 'Thing 1', value: 1 },

  { label: 'Thing 2', value: 2 },

  { label: 'Thing 3', value: 3 },

  { label: 'Thing 4', value: 4 },

  { label: 'Thing 5', value: 5 },

];


const UserForm = (props) => {

  const {

    values,

    touched,

    errors,

    dirty,

    isSubmitting,

    handleChange,

    setFieldValue,

    handleBlur,

    handleSubmit,

    handleReset,

  } = props;


  const _handleSelect = (selectChoice) => {

    setFieldValue('imaginaryThingId', selectChoice.value);

  };


  return(

    <form className="p-5" onSubmit={handleSubmit}>

      <h1>Hello this is form!</h1>

      <div className="form-group">

        <label>Imaginary Email</label>

        <input name="email" type="text" 

          className={`form-control ${errors.email && touched.email && 'is-invalid'}`}

          value={values.email} 

          onChange={handleChange}

          onBlur={handleBlur} />

        {errors.email && touched.email && <div className="invalid-feedback">{errors.email}</div>}

      </div>

      <div className="form-group">

        <label>Imaginary Username</label>

        <input name="username" type="text" 

          className={`form-control ${errors.username && touched.username && 'is-invalid'}`}

          value={values.username} 

          onChange={handleChange}

          onBlur={handleBlur} />

        {errors.username && touched.username && <div className="invalid-feedback">{errors.username}</div>}

      </div>

      <div className="form-group">

        <label>Imaginary Thing</label>

        <VirtualizedSelect

          name="imaginaryThingId"

          value={values.imaginaryThingId}

          options={imaginaryThings}

          onChange={_handleSelect} />

        <small className="form-text text-muted">

          This is optional

        </small>

      </div>


      <button type="submit" className="btn btn-outline-primary" disabled={isSubmitting}>

        {isSubmitting ? 'WAIT PLIZ' : 'CLICK ME'}

      </button>

    </form>

  );

}


export default Formik({

  mapPropsToValues: (props) => ({ 

    email: props.user.email,

    username: props.user.username,

    imaginaryThingId: props.user.imaginaryThingId,

  }),


  validationSchema: Yup.object().shape({

    email: Yup.string().email('Invalid email address').required('Email is required!'),

    username: Yup.string().required('This man needs a username'),

  }),


  handleSubmit: (values, { setSubmitting }) => {

    setTimeout(() => {

      // submit them to the server. do whatever you like!

      alert(JSON.stringify(values, null, 2));

      setSubmitting(false);

    }, 1000);

  },

})(UserForm);


Here Formik injects a few handy props into our form component. You can customize mapPropsToValues, validationSchema, handleSubmit. Here is an example for email validation.
Yup.object().shape({
  email: Yup.string().email('Invalid email address').required('Email is required!'),
  username: Yup.string().required('This man needs a username').when('email', (email, schema) => {
    if (email === 'foobar@example.com') { return schema.min(10); }
    return schema;
  }),
});
When the email is example@foobar.com we add a min rule to the schema. When you want to change the label of the error message according to condition , add ${path} to whatever message you want to display.
Yup.object().shape({
  email: Yup.string().email('Invalid email address').required('Email is required!'),
  username: Yup.string().required('This man needs a ${path}').when('email', (email, schema) => {
    if (email === 'foobar@example.com') { 
      return schema.label('papidipupi').min(10);
    }
    return schema.label('babidibiba');
  });