Dealing with forms in React/Redux — A simple pattern

Jonas Jensen
3 min readFeb 25, 2017

--

Dealing with form state in Redux is tedious. I felt this way for some time after my introduction with React/Redux. This post demonstrates a simple way to sync form state with the Redux store without any additional dependencies.

Even after getting well acquainted with the ins and outs of React and Redux, one fundamental aspect was still unclear to me: how to synchronise input fields with Redux state efficiently? Traditional HTML allows you to group input fields inside a <form> element and submit the form as a unified entity. However, React aims to be a complete abstraction layer over the DOM. Letting React control input field state also means that we have direct access to said state and don’t have to query the DOM for it. This principle is elaborated on in Facebook’s official documentation on controlled components.

Facebook’s documentation does a good job of demonstrating the basics, and also providing an example of the technique we’ll use to handle any number of input fields. By using the name attribute of our inputs to associate them with their respective state fields, we can make our reducers handle all fields declared in the state.

formReducer.js assumes that new changes in any input field will be dispatched through action dispatchers using the CHANGE_INPUT_VALUE type, and that the action will have respective name and value properties set, which we pick out using object destructuring in in line 4.

In line 7 of the snippet above, the received value is paired up with its field using the name as object key. This object is merged into the of the state. And that’s all there is to it for our reducer. ES2015 allows us to write concise code — notice how you don’t even have to couple this reducer to any fields.

FormView.jsx puts it all together. We have some input fields with their respective name attributes. These fields share the same onChange method that triggers an action dispatch using the information in the onChange event. From this standard JS event, it picks out the name of the changed field and the field’s new value, which are sent to the action creator.

The CHANGE_INPUT_VALUE type is simply a string that’s extracted to a constant to have typo-proof references to types. A nice thing to have, but not completely necessary.

And that’s it. If we type in some values in our fields and inspect our state store with Redux Dev Tools extension, it looks like this:

Now, let’s say our use case is getting input about both personal and company information. We’re interested in grouping up our form data into two objects in the store, personInfo and companyInfo. How would we scale this up to deal with multiple forms? Turns out, the answer is quite simple: we just need separate reducers, dispatchers and types for each form.

The updated MainView.jsx shows the implementation for this. We see state from each reducer mapped to the respective input fields, and the fields call different onChange handlers based on which object they belong to. The code for the other parts (actions, types, reducers) is the same, but duplicated for each form group.

Don’t worry about the code duplication — at this point, flexibility trumps optimisation. There are various tweaks we could do to reduce the duplication if the need should arise.

The complete source code for the complete example project can be found here.

--

--