How to Create a Redux-Form with Validation and Initialized Values

How to Create a Redux-Form with Validation and Initialized Values

You want your React app to have an intelligent form that validates the data being input before sending it off to your API. You want it to be easy and straightforward to implement with the features you’d expect. Features like setting initial values of your fields. Luckily for you, Redux Form makes all that a breeze. Even better, with the latest release candidate (Redux Form 6.0.0rc3) and later, you can upgrade to the latest version of React and not have those pesky unknown props errors bring your project to a screeching halt.

This tutorial is going to help you set up a Redux Form that uses the latest syntax, and how to get that form set up with some simple validation and initial values. We’ll be pretending that we’re creating an “update user information” form for a hypothetical application. The form is going to have access to actions to make submissions, and we’ll work under the assumption that we’ve stored our user information in the user reducer.

The complete source code for this tutorial can be found at this gist.

Install the Redux Form 6.0.0 release candidate (or later)

We’re going to be using the latest Redux version (at the time of this writing), 6.0.0-rc.3 for this tutorial. This is because with the changes made in React 15.2 (and later) standard releases of Redux-From don’t work without throwing a plethora of bugs. Furthermore, the syntax of Redux Form has been modified to streamline and simplify the process of creating and managing your forms. There’s no point in learning a syntax that’s going to be absolute as soon as the release candidate is published, so let’s get a head start!

Open up your console and use NPM to install the Redux Form release candidate:

npm install --save redux-form@6.0.0-rc.3  

Our tutorial will also be dependent on react and react-redux, so make sure you have the latest versions of those installed as well.

Setting up your component

Opening up a blank document we want to import the dependencies we’re going to need to create our form. The form we’re making is connected to our application state, and will have an awareness of the actions we’ve created elsewhere in the project. This allows our form to send values to an API or another service directly.

import React, { Component } from 'react';  
import { Field, reduxForm, initialize } from 'redux-form';  
import { connect } from 'react-redux';  
import * as actions from '../../actions';  

Next, let’s scaffold out our component real quick:

class ReduxFormTutorial extends Component {

  //our other functions will go here

  render(
    return (
      <div>
          //our form will go here
      </div>
    )
  )
}

function mapStateToProps(state) {  
  return {
    user: state.user
  };
}

export default connect(mapStateToProps, actions)(form(ReduxFormTutorial));  

You’ll notice that we brought in our application state (user) and set it as props at the bottom. This is going to allow us to initialize our form with data that’s already defined in our state.

Defining your form

The first thing we want to do is define our form. So just underneath our dependencies, outside of the scope of the component, add the following:

const form = reduxForm({  
  form: 'ReduxFormTutorial'
});

Handling the validation of our form can get messy if we do it “inline” as part of the render function of our component. So to clean that up and make it reusable (plus easier to manage), create a const that returns the input and logic for any errors that our field receives:

const renderField = field => (  
    <div>
      <label>{field.input.label</label>
      <input {...field.input}/>
      {field.touched && field.error && <div className="error">{field.error}</div>}
    </div>
);

Let’s also create a similar constant that will serve our select input:

const renderSelect = field => (  
  <div>
    <label>{field.input.label</label>
    <select {...field.input}/>
    {field.touched && field.error && <div className="error">{field.error}</div>}
  </div>
);

Now we need to define the redux form required property handleSubmit inside the render function of the component. Without this, the form simply will not work at all, and you’ll get a bunch of ugly errors.

const { handleSubmit } = this.props;  

It’s time to start making up our form! Inside the render() function return the following example form. Make sure to use the <Field/> component imported from redux form in place of <input />.

    return (
      <div>
        <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>

          <Field name="firstName" type="text" component={renderField} label="First Name"/>
          <Field name="lastName" type="text" component={renderField} label="Last Name"/>
          <Field name="sex" component={renderSelect} label="Gender">
            <option></option>
            <option name="male">Male</option>
            <option name="female">Female</option>
          </Field>
          <Field name="email" type="email" component={renderField} label="Email" />
          <Field name="phoneNumber" type="tel" component={renderField} label="Phone Number"/>

          <button action="submit">Save changes</button>
        </form>
      </div>
    )

We now need something to happen when the onSubmit function is called. Generally, this would mean calling an action and sending that action the values from our form.

  handleFormSubmit(formProps) {
    this.props.submitFormAction(formProps);
  }

At this point, your form should function properly, that is if this.props.submitFormActionwere to point to an existing action that we had created. However, our form doesn’t have any sort of validation or initial data prefilled into the fields. And those are nice, we want those.

Initialize your form with data

For our example here we’re pretending that our form handles updates to our user’s information. We wouldn’t want them to have to type in all of their information every time they switch email accounts or phone numbers. So we want the form to initialize with their existing information which can then be altered in whatever way they wish.

Inside our component, let’s call a function we’ll name handleInitialize when the component mounts.

  componentDidMount() {
    this.handleInitialize();
  }

Now, we can create our function and define the initial values. Afterward, we call the redux form property initialize and pass it our data. The objects names must correlate with name property of our <Field />‘s above.

  handleInitialize() {
    const initData = {
      "firstName": this.props.currentUser.firstName,
      "lastName": this.props.currentUser.lastName,
      "sex": this.props.currentUser.sex,
      "email": this.props.userEmail,
      "phoneNumber": this.props.currentUser.phoneNumber
    };

    this.props.initialize(initData);
  }

It’s as easy as that. When the component mounts, it will define our values and push it to the form’s fields.

Adding form validation

The last thing we want to do now is add in some sort of form validation to make sure all the fields have something in them and it’s of the appropriate format. Outside of our component, we want to define a function called validate that will take our formPropsand run them through various tests.

function validate(formProps) {  
  const errors = {};

  if (!formProps.firstName) {
    errors.firstName = 'Please enter a first name';
  }

  if (!formProps.lastName) {
    errors.lastName = 'Please enter a last name';
  }

  if (!formProps.email) {
    errors.email = 'Please enter an email';
  }

  if (!formProps.phoneNumber) {
    errors.phoneNumber = 'Please enter a phone number'
  }

  if(!formProps.sex) {
    errors.sex = 'You must enter your sex!'
  }

  return errors;
}

We’re going to make a quick jog back up to where we defined our form and add one more line to check our properties against our validation criteria. This process will also check our fields against HTML validation that was defined when we set the <Field />property type to “email” (for example).

const form = reduxForm({  
  form: 'ReduxFormTutorial',
  validate
});

And there you have it! Your redux form is now set to initialize with values, validate itself before submitting, and then pass it’s approved values to your action. Redux form is truly one of the most pivotal dependencies you will integrate into your application so getting a strong understanding of it is important.

That’s all for now and thanks for reading! Once again, you can view the complete source code here. And if you have any questions, comments, or want to suggest a topic for me write about next, just leave it in the section below!

By | 2016-08-06T23:33:37+00:00 August 6th, 2016|Development, Javascript|33 Comments

About the Author:

  • quirksmode

    Thanks for this tutorial, it was really helpful. I must admit I have battled a bit with version 6 of redux-form. I have found that the renderField works great for simple, traditional input fields, but does not seem to work so well for selects or multiple checkbox groups. In your example you have validation on everything except the select, I am interested to know how you might achieve adding this.

    If you were developing a large application with multiple forms, how might you abstract the renderField and the validation to become reusable. This is something I could do with version 5, but am struggling to get it working for version 6.

    • Hey quirkmode, thanks for reading! I am glad it was helpful. So I went in and played with your question and came up with this solution: https://gist.github.com/dmeents/13739fffa28e89470f45f7ee949ab89e

      Validation works just as well with the field, it was a lapse in my part not to include it. I will go back and update that. As for making the validation reusible I was able to make a single ‘form_validate’ file and just import it into all of my forms. However, field naming conventions would need to be more strict in my opinion to make this work. I really do like how it cleans up my components though, so I’ll probably start doing this from now on. Even if it means just exporting different form validations from that one file, it just looks cleaner and keeps it much more simple.

      The one thing I haven’t done yet is verify that you could do something similar with the “renderField” components. I feel like handling passing the field props, the form state and values, etc would be more difficult then efficient in that case.

      • quirksmode

        Huge thanks for getting back to me so quick, will take a look 🙂

    • Hey quirksmode, I wanted to follow up with you. I moved all my fields into another file and exported them. It works perfectly when you import them into your forms, like you suggested. It’s amazing, cleans everything up beautifully and prevents a lot of redundancies when making multiple forms across your application. Thought you’d like to know!

  • Daniel Billingham

    Great read, there doesn’t seem to be anything tying this to the redux implementation from what I can see. I can not see why I can not use this with other flux implementations or just react on its own. Is this correct? If so, is the name, redux-form a little restrictive maybe?

    • Emanuele Ingrosso

      Well you also need to setup a form reducer on the redux store, because the form data and status will live there.

  • Kirat Saluja

    Really helped thanks a lot 🙂

  • Vijay

    Thank you. What if, phonenumber field has to allow user to enter only numbers and validate as the user types in and show error message instantly.I tried with field.dirty but that shows “phone number is required” always which should happen only on blur.Is there any way of achieving this redux-form?

    • It would be as easy as throwing in another test case in your validate file! Here’s a quick jsbin to test: https://jsbin.com/dohudifeya/edit?js,console

      “`
      if (formProps.phoneNumber) {
      var phoneTest = /^+?([0-9]{2}))?[-. ]?([0-9]{4})[-. ]?([0-9]{4})$/;
      if (!phoneTest.test(formProps.phoneNumber)) {
      errors.phoneNumber = ‘Please enter a valid phone number!’
      }
      }

      “`

      • Vijay

        Thank you for the reply.But the problem with that will be i can see the error message only after phone number looses focus.Requirement is to show the message as user types.I got it using event’s onchange method but i would like to know if it can be done by redux-form.

  • @David Meents Thanks for the awesome post,

    just to metion there is a type in the following to code block

    “`
    const renderSelect = field => (

    {field.input.label

    {field.touched && field.error && {field.error}}

    );
    “`

    “`
    const renderSelect = field => (

    {field.input.label

    {field.touched && field.error && {field.error}}

    );
    “`

    Closing parenthesis missing `{field.input.label`

  • Jevgeni Kapparov

    Hey! Im looking for an example with onChange. so if i have 2 fields, as soon as i change first field, i need to change value in second. Do you have any examples?

    E.g. if you change Country then it auto selects phone prefix.

  • Anton Behaeghe

    If I’m doing a request first to get the form-data, how do I wait until the data is in my props to initialize the form?

  • Emmanuel Wayne

    this is really helpful. Do you have anything similar tutorials but for image uploads, sir?

    • Hey, thanks for reading and the suggestion. I do not have any tutorials on image uploads – yet! But I will add it to my list and let you know when it’s finished. 🙂

  • Leo Tucker

    Just missing the } on {field.input.label} . 🙂

  • Thanks, helped me get the migration to v6 working, I was just stuck getting my actions into the form.

  • Paki

    really appreciated, but reset is not working..

    Reset

    when I click on reset, it’ll reinitialize the values.
    any help?

    • Hey Paki, for your ‘onClick’ method, are you calling the ‘this.props.initialize(”)” function from redux form?

  • deyvid yury

    Thank you so much. After the whole morning trying to initialize a form, your solution worked perfectly. Very simple. Once again, thank you.

    • You’re quite welcome! Thank you so much for reading!

  • Abhijeet Jaiswal

    I just keep getting error handleSubmit is not a function . Can you please tell me how to get rid of this?

  • Lucas Gonzalo Michailian

    This line: this.props.initialize(initData); Save my day !

  • Sunil Kumar Banjare

    Great example Have one doubt.
    How can we autofill the data when we already have some data like contact number, address, want whenever click on edit button, call on method and it should be autofill with given data?

  • Malik Mazhar

    i have been trying to find a solution to initialize my form with props and local state for 2 weeks and gave up, your article solved it in minutes with componentDidMount ……….. Great

  • Malik Mazhar

    Hi, it all worked but when try to initialize i can see my prop values in console.log but cant see in input and cant change it manually by typing as well ..
    “firstName”: this.props.currentUser.firstName, it shows my this.props.name in console and if i submit it works but cant see in input and cant type anything, field is locked .. please help

  • sumit kumar

    Thank you so much for this great article, I have found similar example:
    https://www.skptricks.com/2018/06/simple-form-validation-in-reactjs-example.html

  • Lee Roberts

    excellent solution. As forms for updating records are pretty common, you might want to submit this to the redux-form folks as an example. There is no equivalent in their documentation.

  • Thanks for this tutorial! Very helpful!

  • Rachel Albritton

    Thank you for this! I was finally able to get this top work as well, but I had to move the handleInitialize function to componentDidUpdate() to accounts for the props not being fully loaded on the initial componentDidMount call