Here's what you can do to make migrating your forms to Redux easier in the future

01 Oct 2017

Here's what you can do to make migrating your forms to Redux easier in the future

You know you don’t need Redux for your form state… yet. Requirements change and apps evolve. You can’t always know in advance. What was perfectly fine to store in the local state might need to be moved to Redux.

Oh, and it can be painful to migrate to Redux.

But it can also be smooth… if you do certain things.

Actually, just one

Make small ‘action reducer’ functions. They would take current state and some details about the action, and return the new state.

function changeEmail(state, newEmail) {
  return { ...state, email: newEmail }
}


changeEmail(state, '[email protected]') // => returns state with the new value of email

They can be literally used with the functional form of setState:

handleEmailChange = (evt) => {
  this.setState(state => changeEmail(state, event.target.value);
};

If you’ve never passed the function to setState, don’t worry. There’s a section about it in React docs. Basically, instead of passing the new state to setState, you can pass it a function which would accept the current state and return a new state.

Logically, this.setState(fn) is similar to doing this:

  const newState = fn(this.state);
  this.setState(newState);

Then, to migrate this to Redux, you’d only need to do a few things:

  1. Instead of calling setState(state => changeEmail(state, ...)), you would dispatch an action: this.props.onChangeEmail(...);
  2. Instead of getting the current values of fields from this.state, you’d use this.props.
  3. The changeEmail function trivially becomes a branch in the reducer:
  function loginFormReducer(state, action) {
    switch (action.type) {
      case 'changeEmail': {
        return { ...state, email: action.newEmail };
      }
    }
  }

Going a bit futher

You can go further and create a local “reducer” in your component.

Here’s a general idea:

Since actions are often accompanied by some relevant data (like the new field value), we need something more than string actions ('increment'). We need action objects ({ type: 'something', otherRelevantData: 42 }).

function changeEmail(newEmail) {
  return { type: 'changeEmail', email: newEmail };
}

class Form extends Component {
 // ...
  reduce = action => this.setState(state => this.reducer(state, action));

  reducer = (state, action) => {
    switch (action.type) { // note we're switching by action.type
      case 'changeEmail': return { ...state, email: action.email };
    }
  };

  render() {
    // ...
    <input
      ...
      onChange={evt => this.reduce(changeEmail(evt.target.value))}
    />
  }
}

If it seems really close to Redux, that’s because it is.

It would be trivial to switch from local state to Redux when a form manages its state this way:

Think your friends would dig this article, too?

Google+
Tumblr
Preview

Know how you tear your hair out when your designer asks to make a nice form?

But what if you could implement the form experience your users deserve?

The Missing Forms Handbook of React can help you breeze through your React forms. You will learn how forms fit into React and see how to implement common form patterns.

The excerpt contains a table of contents and two chapters: on building an intuition for forms and handling various form controls.

No spam. I will occasionally send you my posts on JavaScript and React.
Preview

Know how you tear your hair out when your designer asks to make a nice form?

But what if you could implement the form experience your users deserve?

The Missing Forms Handbook of React can help you breeze through your React forms. You will learn how forms fit into React and see how to implement common form patterns.

The excerpt contains a table of contents and two chapters: on building an intuition for forms and handling various form controls.