As my classmates and I expand our React skills to follow the Redux pattern, we are moving to a paradigm where we let the global store manage state and moving away from dealing with the state directly. However, there are a few exceptions, one of which is how to deal with user input from a form. Here’s one example of how to handle user input with vanilla React:
In the code above we’re using
setState() on a specific component to set the value of the user input from the form and managing that state locally in the component.
From a Redux Point of view, this is totally fine for organizing state, and the Redux docs on Organizing State say as much:
There is no “right” answer for this. Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component’s internal state. Using local component state is fine. As a developer, it is your job to determine what kinds of state make up your application, and where each piece of state should live. Find a balance that works for you, and go with it.
However, for me personally, managing state in a child component while also using the Redux pattern is a little bit outside the mental model that I’m working toward and a bit of an anti-pattern that I would like to avoid. As a result, I approached managing form input differently, using a
ref to capture the user input. See below:
In this case, I’m using a
ref callback to store a reference to the DOM element, then dispatching that value directly to the store, as opposed to managing the state locally with
setState() in that component.
The tradeoff between the
setState() approach and the
ref approach is that with
setState() you are tracking state with a child component, but with
refs even though you are sending state directly to the store, you are also directly accessing the DOM to pull that value. Neither option is 100% compliant to the React/Redux pattern, so it’s a matter of preference where to break convention - do what feels best for your mental model and your project.
A third way to approach the task is with the mindset that form state is something that should be managed on the application level state, and accordingly build out a form reducer that updates the current value of the form.
Refs can be useful in a few other contexts:
- Managing focus, text selection, or media playback.
- Triggering imperative animations.
- Integrating with third-party DOM libraries.
Let’s take a look at the first case, managing focus. Using a
ref to access the DOM is a great solution for when we have a simple HTML form and want to focus the form field when a user clicks or is otherwise moving through the form:
In this case, you would want to use a
ref since you do want to directly reference that DOM element.
refs should be used sparingly, and only really if you can’t do something declaratively. But there are a few cases when they are very useful!
Do I have to put all my state into Redux? Should I ever use React’s
Refs and the DOM