You are using controlled input components to make your forms. Because your form has to provide immediate feedback, because you need the UX to be top-notch.
You are using Redux to manage your app’s state: things like current user and their data and so on.
At this point, you look at these two things and are kind of wondering:
Should I put this form’s state into Redux? Should I have all form state in Redux?
Well, should you?
React state vs. Redux state
As Dan Abramov put it:
Use React for ephemeral state that doesn’t matter to the app globally and doesn’t mutate in complex ways. For example, a toggle in some UI element, a form input state. Use Redux for state that matters globally or is mutated in complex ways. For example, cached users, or a post draft.
The simplified version of the quote is: use React state for things that don’t matter globally, and use Redux for state that does matter.
He has a point. He did put form input state into the ephemeral category, but that’s not always the case, and I’ll show why.
Applied to forms
That’s… good and all. What does it mean in practice, applied to forms?
Here are several reasons you might want to move that state into Redux:
You want the input value to outlive the component.
That is, even after the form gets unmounted, you still want to access its state.
For example, if you enter your email into a login form, then close it, and then want to come back and see it. Another example would be saving a message draft when a user switches to another conversation.
This was also the case in Jambler, where we needed to preserve half-filled bet questionnaires.
If the input needs to survive page refreshes, storing them in Redux would be a good call, too (and then using something to save that part of the state tree in
You have to have several instances of the form, synced.
It’s not unheard of to have a login form in a modal, but also have some places in your app where the login form is embedded right there. Think a landing page.
Or, continuing the messaging example and drafts, you may have several ways to message. Facebook, for instance, has a messaging widget on every page, but it also has a separate messaging page. It currently does not save the drafts between these do, but it by all means could.
In those cases, you might want to sync their inputs with Redux, so that two forms at the same time can have them.
You want to share particular input between different forms.
This is a generalization of the previous case. A typical example would be entering your email into a login form, then clicking “Forgot password” and… seeing that other form have your email already!
You want certain form state to have the impact on the rest of your app.
Like, show a spinner in the navigation bar while the form is being submitted.
Or make Clippy cover his eyes when a user enters their password.
(The depicted case doesn’t need Redux as the owl is part of the form. However, if your app has a persona that lives somewhere globally, like Clippy, this would apply.)
Your imagination is the limit here, really, but if anything in the form — some value, or whether some input is active, or such — is needed outside the form, Redux is where it’s at.
On another hand, here are the broad reasons to keep the state in a React container:
The form is one-off.
It’s short-lived, it exists in only one place. Simple as that, not every form needs its inputs to be persisted after it is closed.
The form’s data isn’t needed outside of it.
Not every form affects the global state of your app, either.
The form’s state is so complex, managing all of that with Redux would be even worse.
Yes, Redux is here to make your life simpler, but the reality is that some things may feel incredibly over-engineered and weird with Redux.
In short, if the form state does not matter globally, it’s more than fine to keep it in the local state.
A sensible default
Most of my forms start out with React state only. And it’s a great default, because nearly not every form needs to implement all those cases when Redux is needed.
However, when the UX person comes and asks for something you can’t have with React state alone, you have to be ready.
In general, structuring your React state and components according to the container/presentational component pattern would make such a React state → Redux transition very easy.
Even if you decide you do need to go down the Redux route, don’t trap yourself into thinking you now have to move every single bit of your container state into Redux.
In fact, this is rarely the case. Instead, identify the state that:
- needs to outlive the form, or
- needs to be available in several instances of the form at the same time, or
- needs to be available in unrelated parts of the app (think Clippy!)
And once you have, make that into Redux state.
For example, if the goal is to persist the input values as in the login modal example, only login and password would go into the state. The piece of state that knows whether a certain input would still stay in the container component, because it’s not needed anywhere else.
No clear-cut answers
Ultimately, there is no “right” or “wrong” answer in the abstract.
There may well be ways to make Clippy cover its eyes without Redux.
There may well be reasons to use Redux even for a one-off form. For example, if time-travel debugging is how you debug every single bug.
Every particular case is different and should be evaluated separately, taking into account:
- current business requirements, and their direction in the near future
- personal, or team, preferences
- added back-and-forth Redux brings
- & so on
And there’s no better person than you to make that call. You don’t need to be compatible with every Medium article out there. Different requirements = different solutions.
BTW. If you want to learn more about handling forms with React, be sure to sign up for my newsletter.Tweet