ref()
| Since: | React 16.8(2019) |
|---|
A ref in React is an object that holds a reference to a DOM element or a class component instance. It takes the form { current: ... }, with the reference stored in the current property. In function components, refs are created with useRef; in class components, with React.createRef().
Structure of a ref Object
// A ref object is a plain object of the form { current: value }
const ref = { current: null };
// Passing it to the ref attribute in JSX causes React to set the DOM node into current after mount
<input ref={ref} />
// After mounting, access the DOM node via ref.current
ref.current; // The <input> DOM node
ref.current.focus(); // You can call DOM methods directly
// After unmounting, current is reset to null
ref.current; // null
Creation Methods
| Method | Overview |
|---|---|
useRef(initialValue) | A hook used in function components. Returns the same ref object throughout the component's lifecycle. Can also be used to hold arbitrary values across renders, not just DOM references. |
React.createRef() | A method used in class components. Creates a new ref object each time it is called. Typically created in the constructor or as a class property with this.ref = React.createRef(). |
| Callback ref | A method that passes a function to the ref attribute. The function is called with the DOM node at mount time and with null at unmount time. Useful when you need fine-grained control over when the ref is acquired. |
Sample Code
This example demonstrates three ways to use refs: DOM access via useRef in a function component, createRef() in a class component, and a callback ref.
import { useRef, useEffect, createRef, Component } from 'react';
// -------------------------------------------------------
// 1. DOM access with useRef (function component)
// -------------------------------------------------------
function FocusExample() {
// Create a ref object with useRef (initial value is null)
// Returns an object { current: null }
const inputRef = useRef(null);
useEffect(function() {
// After mounting, inputRef.current is set to the <input> DOM node
// Call focus() to focus the input immediately on page load
inputRef.current.focus();
}, []);
function handleShowValue() {
// Access DOM properties directly through ref.current
alert('Input value: ' + inputRef.current.value);
}
return (
<div>
{/* Pass the ref object to the ref attribute */}
<input ref={inputRef} type="text" placeholder="Type here" />
<button onClick={handleShowValue}>Check value</button>
</div>
);
}
// -------------------------------------------------------
// 2. DOM access with createRef() (class component)
// -------------------------------------------------------
class ClassFocusExample extends Component {
constructor(props) {
super(props);
// Call createRef() in the constructor to create the ref
// Storing it on this makes it reusable throughout the lifecycle
this.inputRef = createRef();
}
handleClick() {
// this.inputRef.current holds the <input> DOM node
this.inputRef.current.focus();
}
render() {
return (
<div>
<input ref={this.inputRef} type="text" placeholder="Class component example" />
<button onClick={this.handleClick.bind(this)}>Focus</button>
</div>
);
}
}
// -------------------------------------------------------
// 3. Callback ref
// -------------------------------------------------------
function CallbackRefExample() {
// With a callback ref, you manage the variable that stores the ref yourself
// Create a "container for the ref" using useRef
const divRef = useRef(null);
// Pass a function to the ref attribute
// At mount: node receives the DOM node
// At unmount: node receives null
function callbackRef(node) {
divRef.current = node;
if (node !== null) {
// Apply a style as soon as the DOM node is received
node.style.border = '2px solid #61dafb';
}
}
function handleClick() {
if (divRef.current) {
// Manipulate the DOM node obtained via the callback ref
divRef.current.style.backgroundColor = '#e8f8ff';
}
}
return (
<div>
{/* Passing a function to the ref attribute creates a callback ref */}
<div ref={callbackRef} style={{ padding: '16px', display: 'inline-block' }}>
Element managed by callback ref
</div>
<button onClick={handleClick}>Change background color</button>
</div>
);
}
// App displaying all three examples
function App() {
return (
<div style={{ padding: '16px' }}>
<h2>Reference with useRef</h2>
<FocusExample />
<h2>Reference with createRef()</h2>
<ClassFocusExample />
<h2>Callback ref</h2>
<CallbackRefExample />
</div>
);
}
export default App;
Overview
A ref is a simple object of the form { current: ... }, with the reference stored in the current property. When you pass this object to the ref attribute in JSX, React automatically sets the DOM node into current after mounting and resets it to null after unmounting.
When working with refs in function components, use useRef. Because useRef returns the same object throughout the component's lifecycle, it safely holds references across renders. In class components, use React.createRef(). Using createRef() in a function component creates a new object on every render, which is not appropriate.
A callback ref passes a function to the ref attribute and allows you to write logic that responds to the moment the ref is set or cleared. It is useful in cases where a static object is insufficient, such as dynamically managing references to each element of a list.
Ordinary function components cannot receive the ref attribute as a prop. To forward a ref to a child component, wrap it with forwardRef. To limit the API a child component exposes to its parent, combine it with useImperativeHandle.
Related pages: useRef / forwardRef / useImperativeHandle
Common Mistakes
Using createRef in a function component creates a new object on every render
In class components, React.createRef() is called inside the constructor to hold the ref. However, using createRef() in a function component creates a new ref object on every render, losing the reference to the previous DOM element. Use useRef in function components.
input_ng.jsx
import React from 'react';
function FocusInput({ label }) {
// A new ref is created on every render, so current is always null
const inputRef = React.createRef();
function handleFocus() {
inputRef.current.focus(); // current is null — will error
}
return (
<div>
<label>{label}</label>
<input ref={inputRef} />
<button onClick={handleFocus}>Focus</button>
</div>
);
}
function App() {
return <FocusInput label="Kiryu Kazuma's input field" />;
}
Fixed:
input_ok.jsx
import { useRef } from 'react';
function FocusInput({ label }) {
// useRef retains the same object across renders
const inputRef = useRef(null);
function handleFocus() {
inputRef.current.focus();
}
return (
<div>
<label>{label}</label>
<input ref={inputRef} />
<button onClick={handleFocus}>Focus</button>
</div>
);
}
Reading or writing ref.current during rendering causes unstable behavior
Read and write refs inside event handlers or useEffect. Reading or writing ref.current during rendering (while JSX is being computed) interferes with React's re-rendering mechanism and leads to unpredictable behavior.
render_ref_ng.jsx
import { useRef } from 'react';
function Counter() {
const countRef = useRef(0);
// Mutating ref.current during rendering (wrong)
countRef.current = countRef.current + 1;
return <p>{countRef.current}</p>;
}
Fixed:
render_ref_ok.jsx
import { useRef } from 'react';
function Counter() {
const countRef = useRef(0);
// Mutate ref.current inside an event handler
function handleClick() {
countRef.current = countRef.current + 1;
console.log('Click count:', countRef.current);
}
return <button onClick={handleClick}>Count (Majima Goro: {countRef.current})</button>;
}
If you find any errors or copyright issues, please contact us.