I'm a big fan of the Open Source Redux Form library - its primary purpose is to make handling form state in Redux applications simple. The general principle is that you define a Redux Form by specifying a React component with a bunch of <Field>s - each with a name property. Your form has a name too. What you end up with in your Redux state is a form object, with a sub-object for your form. Each <Field> is a connected component - it's hooked up to the state and will raise actions when the value changes. Validation is supported too.

Redux Form Logo

One of the tasks I frequently run into is the need to have a form for creating (let's say, a user). Later, a requirement comes down to also support editing. We'd like to re-use the form we designed for creation, alongside all of the validation. How can we do this? It's actually incredibly easy!

Let's take a look at an incredibly trivial Redux Form, with some simple validation:

import React, { PropTypes } from 'react';
import { reduxForm, Field } from 'redux-form';

const UserForm = ({ onSubmit }) =>
  <form onSubmit={onSubmit}>
    <label><Field name="id" component="input" type="text" /> ID</label>
    <label><Field name="name" component="input" type="text" />Name</label>
    <button type="submit">Submit</button>
  </form>;

const validate = (values) => {
  const result = {};

  if (!values.id) {
    result.id = 'Please enter a user id';
  }

  if (!values.name) {
    result.name = 'Please enter a name';
  }

  return result;
};

export const CreateUserForm = reduxForm({
  form: 'createUser',
  validate
})(UserForm);

Pretend for now that this is a more complicated form, with lots of custom form elements, business logic validation rules and looks stunning. If we want to re-use this for editing, then we'll want to retain all of that. How can we do it?

Firstly, note that the binding of the form component to the redux state is done via the redux-form decorator. This is where we give the form an identifying name and hook up the validation logic. This actually leaves the underlying form component entirely reusable - all we have to do is give the form a different name!:


export const EditUserForm = reduxForm({
  form: 'editUser',
  validate
});

Customising the Form

Nice! Okay, let's now say that a requirements comes in that only some fields can be edited in your form. How can we implement this?

I'd introduce a property passed to the form component to identify the mode that we're using the form in. Something like:

UserForm.propTypes = {
  mode: PropTypes.oneOf(['create', 'edit']),
  onSubmit: PropTypes.func
};

To set the prop and ensure that it's passed through to the form component correctly, we have to slightly change the code above. We introduce an intermediate component which renders the underlying form component:

const CreateUserForm = props =>
  <UserForm {
    ...props,
    mode='create'
  } />;
const EditUserForm = props =>
  <UserForm {
    ...props,
    mode='edit'
  } />;

export const ConnectedCreateUserForm = reduxForm({ ... })(CreateUserForm);
export const ConnectedEditUserForm = reduxForm({ ... })(EditUserForm);

Other props that are passed to the ReduxForm components (the <Connected * UserForm> ones), such as onSubmit, will be passed through too, as I'm use property spreading - a neat feature provided in ES6 via the Object Spread operator.

Now, when we render the form (either <CreateUserForm /> or <EditUserForm />) the mode is set to create or edit appropriately. We can use this prop to determine whether the id field is enabled:

const UserForm = ({ mode, onSubmit }) =>
  <form onSubmit={onSubmit}>
    <label><Field name="id" component="input" type="text" disabled={ mode === 'edit' } /> ID</label>
    <label><Field name="name" component="input" type="text" />Name</label>
    <button type="submit">Submit</button>
  </form>;

You could also do something like altering the form title, based on the mode:

const UserForm = ({ mode, onSubmit }) =>
  <form onSubmit={onSubmit}>
    <h2>{ mode === 'edit' ? 'Edit' : 'Create' }</h2>
    ...
  </form>;

Conclusion

This might be a simple example, but it's a good demonstration of the power of React and of component composition. As it's the decorator (the call to reduxForm) that controls where on the state model we look, everything underneath that is free to operate without knowledge of a state model. I think this is a great credit to the design of Redux Form.

One final point to make - how much you go down this route really depends on how close your create/edit forms turn out to be. I'd be happy with a bit of if ... else logic in a common component as long as it doesn't become too gnarly. But for me it strikes a decent balance between re-usability and customisation.