React/ReactJS: Refs

In React's one-way (or "unidirectional') flow of data, the parent components interact with children via props.

However, in some cases you might need to directly access the attributes of some elements of a child component and/or modify them, without re-rendering them with updated props. This is where refs come in handy. Refs are kind of attributes that offer access to React elements created by the render() method. Refs modify the actual DOM contrast to the virtual DOM philosphy of ReactJS.

The official ReactJS documentation here cites the following three reasons to use refs:

We create refs using the React.createRef() API (introduced in React 16.3, March 2018), which are then added to the JSX elements with the ref attribute. The below code illustrates how it is used.

					
						class SomeComponent extends React.Component {
						  constructor(props) {
						    super(props);
						    this.someRef = React.createRef();
						  }
						  render() {
						    return <div ref={this.someRef} />
						  }
						}
					
				

The passed ref offers access to the referenced node with the current attribute.

					
						const node = this.someRef.current;
					
				

In the below section, we make use of ref's current attribute to auto-focus on an <input/> element.

Using Ref to Focus in an Input Element

The ref attribute is passed to the <input/> DOM element. Using this ref's current attribute, the <input/> element's focus() method is invoked inside componentDidMount() to automatically focus on it right after the component loads.

						
							class TextFocus extends React.Component{
							  constructor(props) {
							  	super(props);
							  	this.nameInput = React.createRef();							  	
							  }
							  componentDidMount() {
							    this.nameInput.current.focus();
							  }
							  render() {
							    return(
							      <div>							      
							        <input 
							          ref={this.nameInput} 	
							          placeholder="Name"						       
							        />
							      </div>
							    );
							  }
							}
						
					

Callback Refs

There is another way to set refs, without the need of passing any ref attribute created by the createRef() API in the constructor. Instead, a function receiving an HTML DOM element or an instance of a component as an argument is passed. It typically looks as follows:

						
							<input type="text" ref={el => this.textInput = el}/>
						
					

In the following section, we will make use of callback ref to reference a <video> element and invoke its play() and pause() methods.

Using Callback Ref to Play/Pause an HTML5 Video

For the purpose of this example, let us import some video of a bird (bird.mp4) inside the /videos directory. I downloaded this silent video for free from https://videos.pexels.com/videos/video-of-a-bird-855097

					
						import bird from './videos/bird.mp4';
					
				

This import name will be substituted as a value for the src attribute of the <source> element.

A callback function is passed to the ref inside the <video> element. This callback stores a reference to this VIDEO node in an instance property.

					
						class Video extends React.Component {
						 constructor(props) {
						    super(props);
						    this.state = {
						      play: false,
						    }
						    this.videoClick = this.videoClick.bind(this);
						  }
						  videoClick() {
						    this.state.play? this.video.pause():this.video.play();
						    this.setState({ play: !this.state.play });
						  }
						  render() {
						    return (
						      <div>
						        <video ref={vd => this.video = vd}>
						         <source
						            src={bird}
						            type="video/mp4"
						         />
						        </video>
						        <div>
						          <button onClick={this.videoClick}>Play / Pause</button>
						        </div>
						      </div>
						    )
						  }
						}
						export default Video;
					
				

Note that we do not put the controls attribute into the <source> element, which would have enabled video controls like play/pause, full-screen toggle, volume adjustments and slider. Instead, we added an additional Play /Pause button below which on clicked makes use of the this.video callback inside its handler to toggle the call between the video element's play() and pause() methods.

Upon rendering, the loaded <Video/> component appears as follows.

Adding Ref to a Class Component

Let us create a class component called <Name/> which has a function called setName() that sets the value of the <input/> element to some string ("Felix" here). Notice that nowhere we have called this function inside the component.

						
							class Name extends React.Component{
							  constructor(props) {
							  	super(props);
							  	this.nameInput = React.createRef();
							  	this.setName = this.setName.bind(this);							  	
							  }
							  setName() {
							  	this.nameInput.current.value = 'Felix';							
							  }
							  render() {
							    return(
							      <div>							      
							        <input 
							          ref={this.nameInput} 	
							          placeholder="Name"						       
							        />
							      </div>
							    );
							  }
							}
						
					

Instead, we call the function from a parent component called <AssignName/> by attaching a ref.

						
							class AssignName extends React.Component{
							  constructor(props) {
							    super(props);
							    this.textInput = React.createRef();
							  }
							  componentDidMount() {
							    this.textInput.current.setName();
							  }
							  render() {
							    return (
							      <Name ref={this.textInput} />
							    );
							  }
							}
						
					

By the way, if both the above components are in the same file, do not forget to export the parent component <AssignName/>.

						
							export default AssignName;
						
					

If the <Name/> component above would have been functional (stateless) instead of a class, ref would not have worked as they do not have instances.

Ref with jQuery, a Third-Party DOM Library

Refs are also used when integrating third-party DOM manipulating libraries like jQuery with React. They are attached to the plugin's wrapper element, which usually is the only child element of the wrapper <div/>, so as to avoid conflicts with React updates. We have a separate tutorial on using jQuery plugins with React here.

Notes

  • Refs should not be overused; avoid them wherever the desired functionality can be achieved declaratively.
  • The ref attribute should not be used on functional components as they do not have instances.