Back

Explore Topics

Subscribe

Stay up to date with
Bizzabo's latest

Follow us

Bizzabo news | 30 January 2017

Using Forms in React-Redux: Tips and Tricks

Royi Schwartz

A while ago I published a blog post about some lessons learned from moving to React and Redux. It has been a pretty long time already that I have been using React and Friends and wanted to share what was one of our biggest pains and how we overcame them — implementing forms.

A lot of web applications are form-based, you give the user the ability to use your platform by filling forms and manipulating form components. This obviously raises some questions regarding how to write and use form components in react, and how react and redux play along together and more, such as:

# How does the component behave?
# Where do I keep my data?
# How do I perform validations?

# How do I detect the form’s state and changes?

At Bizzabo, a lot of our pages in our service are form based, it has been for a while so we are aware of the challenges and we addressed the items above already when we used Backbone.js, but hey, React is a different playground and we needed on one hand make it seamless to the user to fill the form, whether he is using our backbone forms or our React ones, but in the same time completely redesign the whole way we use forms and answer these questions all over again.

Before we start answering the questions, let me start from the end, we used redux-form — a form state management library on top of redux, Created by Erik Rasmussen, a highly maintained library that changes and evolves on a weekly basis.

# How Does the Component Behave?

Every form component in our system has to have a user-interface behavior. Take an input for instance, it has many states: is valid, is touched, is focused, is dirty, and many more states. for every state you want to have a visual representation of this state. display errors, warning etc. We chose Redux-form’s solution for that, which provides meta information about the state of your component. How do I use a redux form component? The <Field/> component is how you connect each individual input to the Redux store (I will elaborate on this subject in my next point). 

<Field name={keyName} component={MyCustomInput} {…this.props} />

The only thing you need to do to activate it, is to wrap you component with a <Field/> component as displayed above, provide it with a name, your component and then you can display UI states as you wish. There are several ways to generate a redux form <Field/>, you can check the docs to see.

So now you can add your UI for each state as you wish.

 const {meta: {error, touched, dirty}} = this.props;
<div>
<input
disabled={isDisabled}
type={type || “text”}
placeholder={placeholder || ‘Enter a value’}
name={name}
/>
</div>
{error && <label className=”error”>{error}</label>}
{touched && <label className=”touched”>{touched}</label>}
{dirty && <label className=”dirty”>{dirty}</label>} 

As you see above, when you use the <Field/> you get for free UI states, so i can display a different notification based on a different state.

#Where Do I Keep My Data ?

One of our main questions we had to answer was where to keep the data. Let me elaborate what were our concerns that we needed to answer: 
Every form element must have an initial value, it can be an empty one in case your form is acting in its “new” state, or some sort of value for an “edit” state. On any changeblurkeyUp (or any other event that you are interested in) you want the value to update. So where do i keep it?

Redux-form’s solution, which is — A Redux reducer that listens to dispatched redux-form actions to maintain your form state in Redux. Your forms will be mounted in the “form” key name , and every form will have a unique name, and accessing it is as simple as form[name].

Below you can see how easy it is to set it up.

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

const reducers = {
event,
account,
user,
form: formReducer
}
const reducer = combineReducers(reducers)
const store = createStore(reducer) 

Redux-form provides selectors for you initial values and your current values. A great thing about using it is that its just redux, you can listen to specific custom action and manipulate your data accordingly, not only on redux-form actions but for your specific actions. Just use a plugin for that.

So we have talked so far about Displaying the current state of the component, and about where we manage the data.

But what about handling the data itself?

# How Do I Perform Validations?

One of the major challenges every form has is validation. When a user input is being submitted (on any other browser event for that matter) its not enough just to update the form component with the new value, you need to validate the value. The questions we had to ask ourselves in this issue are: Do I keep the form component value in the state and once the validation passes I send it to the store? or do I perform all my data validation in the store?

Redux form has answered all that for us, as validations are part of the library ecosystem. You can pass your form you created using redux form, a validation method, or even perform a validation on a specific <Field/> (from a specific version). It only has 1 constraint, and its the structure of the error object, that is: { field1: <String>, field2: <String> }.You can implement yourself the validation method or use a 3rd party library. we chose the latter and use validator.js, it covers a very large amount of validations, support plugins for special validations and most importantly, returns the error object as required by redux form.

 const validate = (data, props) => {

const rules = {
‘ga-id’: [‘regex:/^UA-\d{4,10}-\d{1,4}$/’],
‘input’: ‘max:50 | required’
};

const messages = {
‘max.input’: ‘This is my max value text’,
‘required.input’: ‘This is my required text’
‘regex.ga-id’: ‘My Google Analytics id format text’
};

const validator = new Validator(data, rules, messages);
validator.passes();
return validator.errors.all();
};

Validation using Validator.Js

In the example above you can see a validation example. You can provide several validation on each field (e.g: input), also you can provide the text for each error and once you run the validation you can return the error object.

#How To Detect Form’s State and Changes

Our last big item we needed to resolve was to detect the current state of the form, and to track its changes. I will give an example — We wanted to detect whether for has changed from its original values, so that when the user tries to navigate we can notify him that he has unsaved changes. Redux Form provides the full visibility of the current form state. You can detect that its dirty, pristine, was it even touched at all by the user (a focus on an element) and more. It also provide an outer API allowing you to trigger state changes you want through redux actions, for example you can submit your form, or reset your form using a redux action no need for an actual submit button if not needed.

In Conclusion

Forms is always tricky, and Yes, every form has its needs, and sometimes you need to find solutions and work arounds, but most on the scenarios are covered by redux-form, and if they aren’t you can easily migrate you solution to work with redux form. For us it is working great and I hope it will work for you as well

Lets work together! Click the button below to explore opportunities at Bizzabo.

Stay up to date with Bizzabo's latest.

You may also
be interested in