Why build your forms with Redux-Form

When I usually create forms for my React/Redux applications I tend to keep the value of the inputs on the application state, with little to no editing, (because my forms are usually simple), I never stopped to realize what that means. But when I and my team at ThoughtWorks faced a project with more complex form requirements, we started to wonder if it was worth to do all that Redux boilerplate to keep our inputs values into our application state.

In our discussion, I heard things like: "It is just a form!", "Do we really need the input values in our application state?".

After a lot of talk, we started to consider using the library Redux-Form by Erik Rasmussen, but it arose other questions like "It will remove our flexibility to make custom behaviors, won’t it?".

The end of this story is that we actually decided to use Redux-Form and I thought that sharing why may save you some time.

Why have the form values on application state?

Let’s get some context

The history of web development shows a move to increase the responsibility of the client side application, which in the past was just the HTML and all the work was made on server — now we have very complex JavaScript applications.

These JavaScript applications have taken the responsibility from the DOM as we could see with famous libraries like jQuery, Angular and more recently React. Since this last one took attention from the community, it brought with it the concept of unidirectional data flow, which basically means your data (the component state or application state if you are using a state manager like Redux) flows down the component tree and events on the UI that changes this data will update only the part of the UI that is under the data source. With that React was the first library to be able to easily render a UI that just represents a group of data that is not actually in the DOM, and that brings up another concept, called controlled components.

But what are controlled components?

Controlled components are just HTML inputs that always receive its value as a property. It also receives an event handler that will update the state when the user interacts with it.

It means that when the user types the letter “J” on the input, what is visible is not the same “J”, it may be an identical “J” that comes from the state, or whatever the event handler has put in there.

Ok but, that doesn’t answer the first question

By having all the application state in the JavaScript app and using controlled components we get a single source of truth and take full control over the application behavior.

In the context of a form, our React component is able to:

  • do instant validation;
  • control the input value format;
  • enable, disable, show or hide components given the state;
  • handle dynamic inputs.

Although it is highly recommended to use controlled components, it is also good to point the drawback that you will have to create event handlers for all your inputs and that may be a bunch of code that doesn’t make sense to the application.

What about Redux-Form?

Now that is known why to keep the form data in the state and you reason if that makes sense for your application we can come back to our main subject. Given that the application uses React and Redux there are two main options: implements for each field an event handler that dispatches an action creators, and the reducer that will receive the action… All the redux stuff. Or we could use a library that does all this work for us.

Redux-Form is a great option to do that job to you. It keeps track of all common application form state such as:

  • The fields that are in the form;
  • The values of each field;
  • The focused field;
  • If the field values are valid;
  • The fields that the user have interacted with;
  • If the form is being submitted;
  • If is happening any asynchronous validation.

Let’s take a look at a bit of code and see how to do a setup.

Here we connect the form component to Redux by decorating it with the high-order component reduxForm. It will also hand us the handleSubmit function, which will take care of the submission behavior.

The Field component takes our input component as its props and acts as a container, bringing the application state to the input component and binding the event handlers to update the state in store.

Look at the InputText component to see the props we receive from the Field.

One important point is that it's still a developer's responsibility to write the form and inputs components, this way the library does not take the flexibility from you to manage the behaviors of your form the way you want, or even add custom ones.

And to finish our integration we add a reducer that will handle the state changes of your form.

Simple isn't it.

Just one more point. Look that the default value of the input is defined when the high-order component reduxForm is called and comes to the input within the prop input and not from the react's prop defaultValue, this way we guarantee that our form values are all represented in the application state.

In summary, having all your form data in application state gives you control over its behavior and you can easily implement that on a React/Redux application with Redux-Form.

I have created a repository on GitHub with the implementation above. I also recommend to check the Redux-Form documentation (which is quite good) and also to watch Erik Rasmussen talk with more information about the library and the reasons to use that. To better understand the controlled component I suggest this post.

Update #1 (2018–10–21)

One of the things people question me when discussing about this post is: 
“Do We really need to use Redux store to keep the form data?”. My answer is no. By the time I wrote this post Redux was hype and Redux-Form didn't had an established alternative, but nowadays we have great options such as Formik and Final-Form, and both use React's component state.
My approach when writing a Redux application is keep all the data that matters to the application in the in the application state as long as it makes sense. But the point is, reason about what make more sense for your application and pick your choice.

Thank's Daniela Araújo and Roberto Soares for the review.

Hope it helps.