Most applications that users on the web use require some type of user input. This includes a signup form, creating posts, or messaging other users. These are all done through common fields. When building your React application, you can manage the state of these forms inside of the component itself or create your own custom Redux implementation. Even though those options are fine, if you’re following the principles of DRY (Don’t Repeat Yourself), it’s wiser to use an option like Redux-Form. It offers the change in the states of your field values, validation and the creation of dynamic forms. In this tutorial, we’ll go over form validation. If you want access to the videos, click here.

Connection to Redux

The first step to adding Redux-Form to your application is to add the formReducer. You only have to add this once to your application because all Redux Forms will be handled by this reducer.

import { createStore, combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'

const rootReducer = combineReducers({
  // ...your other reducers here
  // you have to pass formReducer under 'form' key,
  // for custom keys look up the docs for 'getFormState'
  form: formReducer
});

Building the Redux Form

By default, you can use regular HTML tags in your JSX to build out your form. You just have to import the redux-form into your component.

import React from 'react'
import { Field, reduxForm } from 'redux-form'

let UserForm = props => {
  const { handleSubmit } = props
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="firstName">First Name</label>
        <Field name="firstName" component="input" type="text" />
      </div>
      <div>
        <label htmlFor="lastName">Last Name</label>
        <Field name="lastName" component="input" type="text" />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <Field name="email" component="input" type="email" />
      </div>
	<div>
        <label htmlFor="admin">Admin</label>
        <div>
          <Field name="admin" component=”input” type="checkbox"/>
        </div>
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}

UserForm = reduxForm({
  // a unique name for the form
  form: 'user'
})(UserForm)

export default UserForm

This form is for creating a user and specifying if they are an admin or not. Inside of the component props, you can specify the input field as the JSX element to be used.

Adding Material UI

Even though you can use the default input fields, you may want to style your application using a set of 3rd-party components. An example of this would be Material-UI.

npm install @material-ui/core

Now inside of your component, import the fields that you intend to use.

import TextField from '@material-ui/core/TextField';
import Checkbox from '@material-ui/core/Checkbox';

Now you can create a custom component that uses the Textfield and CheckBox Material-UI components.

const renderTextField = (
  { input, label, meta: { touched, error }, ...custom },
) => (
  <TextField
    hintText={label}
    floatingLabelText={label}
    errorText={touched && error}
    {...input}
    {...custom}
  />
);

const renderCheckbox = ({ input, label }) => (
  <Checkbox
    label={label}
    checked={input.value ? true : false}
    onCheck={input.onChange}
  />
);

These take input and label as props. That way these components can be reusable if you have multiple Text or Checkboxes.

Now you can swap out the regular input fields for your custom components

let UserForm = props => {
  const { handleSubmit } = props
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="firstName">First Name</label>
        <Field name="firstName" component={renderTextField} type="text" />
      </div>
      <div>
        <label htmlFor="lastName">Last Name</label>
        <Field name="lastName" component={renderTextField} type="text" />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <Field name="email" component={renderTextField} type="email" />
      </div>
	<div>
        <label htmlFor="admin">Admin</label>
        <div>
          <Field name="admin" component={renderCheckbox} type="checkbox"/>
        </div>
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}

UserForm = reduxForm({
  // a unique name for the form
  form: 'user'
})(UserForm)

export default UserForm;

Now, you should be able to see the Material-UI components.

Adding Validation to Redux Forms

Adding client-side validation keeps users from entering wrong information. Let’s add validation to make sure that our users enter the first and last name as well as make sure they have a valid email address.

const validate = values => {
   const errors = {};
   const requiredFields = [
    'firstName',
    'lastName',
    'email',
   ];
   requiredFields.forEach(field => {
    if (!values[field]) {
      errors[field] = 'Required';
    }
   });
   if (
    values.email &&
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
   ) {
    errors.email = 'Invalid email address';
   }
   return errors;
}

You can also add asynchronous validation to check that the user’s email is not already in use.

import {checkEmail} from '../services/users';

export default (async function asyncValidate(values /*, dispatch */) {
   checkEmail(values.email).catch(error => {
     throw { email: 'Email already Exists' };
   }); 
});

 

This imports a service that checks the web API to see if previous users have the same email address. If so, then return an error.

Now we can add validation to the form.

UserForm = reduxForm({
  // a unique name for the form
  form: 'user',
validate,
asyncValidate,

})(UserForm)

export default UserForm;
User Creation Redux Form

User Creation Redux Form

Conclusion

Managing your forms should always be made as easily as possible. Don’t repeat yourself and create event handlers for every input field. Along with Redux Form, you also have libraries like formik and final-form. If you’re interested in learning more, check our video courses here.

Codebrains Newsletter

Get weekly dev news and tutorials.

Powered by ConvertKit