Refs, React & Redux

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class NoteCreate extends React.Component {
constructor(props){
super(props)
this.state = {note: ''}
}
handleInputChange(event){
this.setState({
note: event.target.value
})
}
render(){
return (
<div>
<h3>Add a Note</h3>
<form onSubmit={this.handleSubmit.bind(this)}>
<input type='text' onChange={this.handleInputChange.bind(this)} value={this.state.note}/>
<input type='submit' />
</form>
</div>
)
}
}

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:

Do I have to put all my state into Redux? Should I ever use React’s setState()?

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class NoteCreate extends React.Component {
handleNewNote(event) {
event.preventDefault()
const text = this.noteText.value
this.props.store.dispatch({type: 'ADD_NOTE',note: text })
}
render(){
return (
<div>
<h3>Add a Note</h3>
<form onSubmit={this.handleNewNote.bind(this)}>
<input type='text' ref={(input) => this.noteText = input} />
<input type='submit' />
</form>
</div>
)
}
}

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.

Tradeoffs

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 and focus()

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:


1
2
3
<input type="text" id="myTextField" value="Text field.">
<p></p>
<button type="button" onclick="focusMethod()">Click me to focus on the text field!</button>
1
2
3
focusMethod = function getFocus() {
document.getElementById("myTextField").focus();
}

In this case, you would want to use a ref since you do want to directly reference that DOM element.

In general, 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!

Reference

Do I have to put all my state into Redux? Should I ever use React’s setState()?
http://redux.js.org/docs/faq/OrganizingState.html

Refs and the DOM
https://facebook.github.io/react/docs/refs-and-the-dom.html

Powered by Hexo and Hexo-theme-hiker

Copyright © 2016 - 2017 Adventures In Coding & Algorithms All Rights Reserved.

© Christina Entcheva 2016