What Are React Refs?
A ref is a special attribute in React that allows you to directly reference an element or component in the DOM.
React’s state and props are part of its declarative model, meaning the UI updates based on changes in data, but refs provide an imperative way to interact with DOM elements or child components.
With refs, you can bypass the typical React data flow and directly manipulate elements.
To create a ref in a React component, you can use the React.createRef() method (for class components) or the useRef hook (for functional components).
Example of Creating a Ref
import React, { useRef } from 'react';
function InputFocusExample() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus(); // Access the DOM element and focus the input
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
// Usage
<InputFocusExample />
In this example:
- inputRef is a ref that holds a reference to the input element.
- The handleFocus function accesses the DOM element using inputRef.current and focuses on the input field when the button is clicked.
When and Why to Use Refs in React
Refs are typically used in situations where you need to access a DOM element or child component directly. Here are some common use cases:
- Managing Focus: When you want to programmatically set focus to an input field, such as when opening a modal or form.
- Triggering Animations: For animations that are not easily managed through React’s declarative state model.
- Accessing DOM Elements Directly: For specific tasks, like reading scroll positions or setting up complex third-party libraries.
- Handling Form Data: When you want to retrieve input values without updating the state continuously.
- Interacting with Third-Party Libraries: Some libraries require direct DOM access, making refs essential.
How to Create and Use Refs
In React, refs can be created in both functional and class components. Here’s a closer look at each approach:
Creating Refs in Functional Components (with useRef)
In functional components, you use the useRef hook to create refs. The useRef hook returns a mutable object that persists throughout the component’s lifecycle. This object has a .current property where the reference is stored.
import React, { useRef } from 'react';
function VideoPlayer() {
const videoRef = useRef(null);
const playVideo = () => {
videoRef.current.play();
};
const pauseVideo = () => {
videoRef.current.pause();
};
return (
<div>
<video ref={videoRef} src="video.mp4" width="320" height="240" />
<button onClick={playVideo}>Play</button>
<button onClick={pauseVideo}>Pause</button>
</div>
);
}
// Usage
<VideoPlayer />
In this example:
- videoRef references the video element.
- playVideo and pauseVideo functions access videoRef.current to control the playback directly.
Creating Refs in Class Components (with React.createRef)
In class components, you create refs using React.createRef(). This method returns a ref object that can be attached to a DOM element or component.
import React, { Component } from 'react';
class TextInput extends Component {
constructor(props) {
super(props);
this.textInputRef = React.createRef();
}
focusInput = () => {
this.textInputRef.current.focus();
};
render() {
return (
<div>
<input type="text" ref={this.textInputRef} />
<button onClick={this.focusInput}>Focus Input</button>
</div>
);
}
}
// Usage
<TextInput />
In this example:
- textInputRef is created using React.createRef().
- The focusInput method accesses the DOM element through this.textInputRef.current and focuses the input field.
Practical Applications of Refs in React
Here are some common real-world applications of refs in React:
Focusing an Input Field
Sometimes, you may want an input field to be focused automatically when a component mounts.
import React, { useRef, useEffect } from 'react';
function AutofocusInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus(); // Automatically focus input on component mount
}, []);
return <input type="text" ref={inputRef} />;
}
// Usage
<AutofocusInput />
Here, useEffect with an empty dependency array ensures the input field is focused immediately when the component mounts.
Handling Form Data Without State
In some cases, refs are used to read input data without updating the state for each keystroke.
import React, { useRef } from 'react';
function UncontrolledForm() {
const nameRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
alert(`Name: ${nameRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={nameRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
// Usage
<UncontrolledForm />
This approach avoids frequent state updates, making it efficient for simple forms.
Accessing Scroll Position
Refs are helpful when you need to track the scroll position of an element.
import React, { useRef } from 'react';
function ScrollBox() {
const boxRef = useRef(null);
const scrollToBottom = () => {
boxRef.current.scrollTop = boxRef.current.scrollHeight;
};
return (
<div>
<div
ref={boxRef}
style={{ height: '150px', overflowY: 'scroll', border: '1px solid black' }}
>
{/* Content */}
</div>
<button onClick={scrollToBottom}>Scroll to Bottom</button>
</div>
);
}
// Usage
<ScrollBox />
In this example, scrollToBottom scrolls the content to the bottom of the div when the button is clicked.
Limitations and Best Practices of Refs
While refs are powerful, they should be used judiciously:
- Avoid Overuse: Refs can bypass React’s state model, leading to potentially unpredictable behavior. Only use refs when necessary.
- Do Not Rely on Refs for Data Flow: Refs should not be used to store data that drives the UI. Instead, use state for data flow and UI updates.
- Avoid Mutating DOM Elements Directly: Direct DOM manipulation can conflict with React’s reconciliation process. Be cautious when modifying elements directly.