Author avatar

Gaurav Singhal

How to Wire Up Redux-Form Bindings to the Form's Inputs

Gaurav Singhal

  • Dec 5, 2019
  • 14 Min read
  • 2,684 Views
  • Dec 5, 2019
  • 14 Min read
  • 2,684 Views
Web Development
React

Introduction

React is a powerful JavaScript-based library used to create single-page applications. Every application will have a way to accept user inputs from end-users who care to interact with the app.

For managing forms in React, react-redux is one of the most widely used packages. It's used to handle various aspects of forms, such as binding form elements, managing validation, submitting forms, and so on.

Other forms are hard to manage, but using redux-form, we can maintain the input’s state pretty easily by storing each element’s value in state and submitting it for further actions.

What is Redux-Form?

Redux-form is one of the best packages for managing forms efficiently.It makes sure that the HTML form uses Redux to store all the information into the state. In addition, it also helps manage form accuracy in terms of data.

Redux-form is a library, and more precisely, it’s a higher-order component (HOC), which is used to manage the form’s state in a Redux store.

But redux-form is not as simple as we think. It also comes with the complexity to manage form initialization, validation, and maintaining fundamental values.

Wire Up Redux-Form with Form Inputs

To use redux-form in a React application, you should have prior knowledge about certain concepts:

  • React fundamentals
  • Redux reducer formReducer
  • Redux HOC reduxForm() and the <Field> component to manage inputs

These are the terms which we need to understand so that we can configure redux-form into React easily. Let’s look at the description of each of them in detail.

  • formReducer() : The formReducer is a kind of function that manages the form value’s update coming from the form component. Configuration of formReducer() has to be made within the root reducer of the application.

  • reduxForm() : The reduxForm() is the main function, a kind of higher-order component that accepts the component name as an argument. It is used to manage the user interaction to the Redux dispatch actions. It is always configured in the component where we have created the form along with the different fields.

  • Field : This is a kind of component wrapped inside the form component, and most importantly, every form element will consider a form’s <Field> to locate element changes.

These are the pillars for configuring and using redux-form into our application. It may seem complicated at first sight, but when you get used to it, it will be fun to implement Redux forms in React.

Let’s jump to a step by step example where we will configure a simple form along with the validation.

First of all, we need to install some dependency after creating a simple React application. The command is given below.

1
npm install redux react-redux redux-thunk redux-form
shell

Store and Redux-Form Configuration

After installing all these above dependencies, we have to create the store and use <Provider> into the root file called index.js, like this.:

1
2
3
4
5
6
7
import { createStore, applyMiddleware, combineReducers } from 'redux';
// the formReducer () function
import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({
  form: formReducer
});
javascript

Here we have used formReducer (), which is used to serve any of the forms into the application so that it is just a one-time configuration.

Then we need to create the store and provide it to the whole application so that the data will sync across the components, like this:

1
2
3
4
5
6
7
8
const store = createStore(rootReducer, applyMiddleware(thunk));

render(
  <Provider store={store}>
   <App />
  </Provider>,
  document.getElementById('root')
);
javascript

Here in this code snippet, we have created a store using createStore () function, which accepts the root reducer of the application, where we have also configured our formReducer as well.

By doing this configuration, we will be able to use forms into our application, and the data will be synced with the changes that are coming from the form component.

The final source code of the index.js file looks something like this.:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { Component } from "react";
import { render } from "react-dom";
// Our simple form
import SimpleForm from "./SimpleForm";
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware, combineReducers } from 'redux';
// the formReducer() function
import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({
  form: formReducer
});

const store = createStore(rootReducer, applyMiddleware(thunk));

class App extends Component {

  constructor() {
    super();
    this.state = {
      name: "React"
    };
  }

  render() {
    return (
      <div>
        <SimpleForm />
      </div>
    );
  }
}

render(
  <Provider store={store}>
    <App />
  </Provider>,

  document.getElementById('root')
);
javascript

We are done with our root component configuration along with the single source of truth (store configuration) into our application.

Form Component

Previously, we created the store and used formReducer, which updates it when the changes are coming from the form component. But for that, we need to have redux-form configured into our application.

Let’s create a new component called SimpleForm.jsx and configure reduxForm () method, like this.:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { Component } from "react";
import { reduxForm, Field } from "redux-form";

class SimpleForm extends Component {

  render() {
    const { handleSubmit, reset, pristine, submitting, valid } = this.props;

    return (
      <div>
        <form onSubmit={handleSubmit(values => console.log(values))}>
            // Actual form fields
        </form>
      </div>
    );
  }
}

export default reduxForm({
  form: "SimpleForm",
})(SimpleForm);
jsx

Let’s look closer at the basic form configuration we have done so far in this form component.

reduxForm ()

As we discussed earlier, the reduxForm () function is a higher-order component (HOC) that accepts the component and also returns the updated component based on the interaction with the form elements.

In this function, we have provided a unique name to the form along with our form component, which is SimpleForm. After using that HOC, now we will be able to access different properties of the Redux form, like handleSubmit, submitting, pristine and so on.

handleSubmit ()

Again, this is the function to submit the form error-free. The function can be accessed via props all the way from the reduxForm() component.

The handleSubmit () is used to submit the field’s data to the form reducer, and the reduxForm () higher-order component returns the processed data if the form contains the required and valid values.

Creating Generic Input Control

After creating the form, we should have different form controls in it so that we can create control, somewhat like the source code given below.

1
<Field type="text" />
jsx

Alternately, we can create a generic form input so that it can be reusable all the time along with the <Field>.

Let’s create a new file called InputControl.js and paste the following line of source code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { Component } from "react";

export const input = ({
  input,
  type,
  placeholder,
  id,
  meta: { touched, error },
  ...rest
}) => {

  return (
	 <div>
      <input {...input} type={type} placeholder={placeholder} id={id} />
      {touched && error && (
       <span style={{ fontSize: "10px", color: "red" }}>{error}</span>
      )}
    </div>
  );
};
jsx

The above example is just a simple file, where we will pass the different properties which can be useful for the input from the <Field> control, which we are going to use in our actual form component.

Now let’s consume that generic input control with <Field>, and the complete source code of the SimpleForm.jsx will look like this:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import React, { Component } from "react";
import { reduxForm, Field } from "redux-form";
import { input } from "./InputControl";

class SimpleForm extends Component {

  render() {
   const { handleSubmit, reset, pristine, submitting, valid } = this.props;

    return (
      <div>
        <form onSubmit={handleSubmit(values => console.log(values))}>
          <table>
            <tr>
             <td>
                <label>First Name :</label>
              </td>
              <td>
                <Field
                  name="firstName"
                  type="text"
                   component={input}
                  id="first-name"
                  placeholder="enter your first name"
                />
              </td>
            </tr>
            <tr>
               <td>
                <label>Last Name :</label>
              </td>
              <td>
                <Field
                  name="lastName"
                  type="text"
                  component={input}
                  id="last-name"
                  placeholder="enter your last name"
                />
              </td>
            </tr>
            <tr>
              <td>
                <label>Email Address :</label>
              </td>
              <td>
                <Field
                  name="email"
                  type="text"
                  component={input}
                  id="email"
                  placeholder="enter your email"
                />
              </td>
            </tr>
            <tr>
              <td>
                <button
                  type="submit"
                  disabled={!valid || pristine || submitting}
                \>
                  Submit
                </button>
              </td>
              <td>
                <button type="button" onClick={reset}>
                  reset
                </button>
              </td>
            </tr>
          </table>
        </form>
      </div>
    );
  }
} 

export default reduxForm({
  form: "SimpleForm",
})(SimpleForm);
jsx

Let’s look at this form component in detail.

  • First of all, we have an import statement for the generic input control .

  • Then we used <Field>, which is used to connect each of the form inputs to the store .

  • Along with <Field>, we have used the component as “input” that we created previously .

  • Based on the form activity, we will be able to disable the button based on three conditions:

    • ​ If the form is invalid

    • ​ If the form is submitting

    • ​ If the form element’s value is not yet changed

  • ​After the form values are valid, then the object of the field values will be returned from the redux-form’s HOC .

As you can see in the above example, we have used three different fields for first name, last name, and email, and now we are done with our simple example.

To check whether the form is working as expected, run this app and see the difference.

Form Validation

We have disabled the submit button until it satisfies all of the conditions which we have configured. But somehow we need a way to validate the input’s value differently.

Redux-form provides the additional property along with the HOC, which is called validate. This means we can pass the values to the validation function, and it returns the appropriate message based on the validation criteria.

Let’s create a new validation helper called FormValidator.js and paste the following lines of code.:

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
export const formValidatorHelper = values => {

  const errors = {};

  if (!values.firstName) {
    errors.firstName = "First name is required";
  } else if (values.firstName.length < 3) {
    errors.firstName = "First name should be > 3";
  }

  if (!values.lastName) {
    errors.lastName = "Last name is required";
  } else if (values.lastName.length < 3) {
    errors.lastName = "Last name should be > 3";
  }
    
  if (!values.email) {
    errors.email = "Email is required";
  } else if (!/(.+)@(.+){2,}\.(.+){2,}/i.test(values.email)) {
    errors.email = "Invalid Email !!!";
  }

  console.log(errors);
  return errors;
};
javascript

As you can see in the validator file, it’s just a simple function that accepts the form values, and based on the condition, it will return the error object to the form component.

Now open the file that we created called SimpleForm.jsx and import the validator function, like this.:

1
import { formValidatorHelper } from "./FormValidator.js";
jsx

After importing the function, we need to pass it to the reduxForm() HOC as value to the props called validate, like this.:

1
2
3
4
export default reduxForm({
  form: "SimpleForm",
  validate: formValidatorHelper
})(SimpleForm);
jsx

That's it. We have completed our example by implementing the redux-form along with the React.

Initially, all of the fields are required, but as soon as we change the value, the message will disappear frequently. But keep in mind that once we touch the form controls, the validation will get activated and show the error message along with the form control. It can be any element, like paragraph, span, and so on.

When we provide the incorrect value to the field, it will return the appropriate message and will also disappear as soon as we provide the valid value.

The example shows that this is how we have implemented our form component, generic input component, and at last, the validator helper function.

Conclusion

In this guide, we got a basic introduction to the redux-form and where we can use it in our applications. In addition, we also learned about the three essential pillars of the redux-form library.

By using the redux-form library, we can easily manage end-to-end form components along with generic input controls and the validation function, which makes the form manageable across the application.

Stay tuned for upcoming advanced guides on React with real-time scenarios. Keep reading.

8