In React, `useRef` is a built-in Hook that allows you to create a mutable ref object whose `.current` property can hold any mutable value. It's primarily used for two main purposes:
1. Accessing the DOM Directly: The most common use case is to get a direct reference to a DOM element (like an input field, a div, or a button) or a React component instance. This allows you to interact with the underlying DOM API directly, for example, to focus an input, trigger media playback, or measure element dimensions. When `useRef` is attached to a JSX element via the `ref` prop, its `.current` property will point to the actual DOM node after the component mounts.
2. Storing Mutable Values That Don't Trigger Re-renders: Unlike `useState`, changing the `.current` value of a ref does not trigger a re-render of the component. This makes `useRef` ideal for storing values that need to persist across renders but whose changes shouldn't cause the UI to update. Examples include timers (e.g., `setInterval` IDs), previous values of props/state, or any value that acts as an instance variable for the component.
How it works:
* `useRef` returns an object like `{ current: initialValue }`.
* When the component re-renders, `useRef` always returns the *same* ref object. This ensures that the reference remains stable across the component's lifecycle.
* You initialize it with `const myRef = useRef(initialValue);`. If you're using it to reference a DOM element, `initialValue` is often `null`.
When to use `useRef` vs. `useState`:
* Use `useState` when you need a value to be part of the component's state, and changes to it should re-render the component to reflect those changes in the UI.
* Use `useRef` when you need to store a mutable value that persists across renders but whose changes should not trigger a re-render, or when you need to directly interact with a DOM element.
Example Code
```jsx
import React, { useRef, useState, useEffect } from 'react';
function RefExample() {
// 1. Using useRef to access a DOM element
const inputRef = useRef(null);
// 2. Using useRef to store a mutable value that doesn't trigger re-renders
const timerIdRef = useRef(null);
const nonReRenderingCounter = useRef(0);
// For comparison: A state variable that DOES trigger re-renders
const [stateCounter, setStateCounter] = useState(0);
useEffect(() => {
// Focus the input field when the component mounts
if (inputRef.current) {
inputRef.current.focus();
}
// Start a timer using useRef to store the interval ID
timerIdRef.current = setInterval(() => {
console.log('Timer running...');
nonReRenderingCounter.current += 1; // Increment ref counter, no re-render
// To show the ref counter value in UI, you'd need a state update or effect
}, 1000);
// Cleanup function: Clear the interval when the component unmounts
return () => {
if (timerIdRef.current) {
clearInterval(timerIdRef.current);
}
};
}, []); // Empty dependency array means this effect runs once on mount
const handleFocusClick = () => {
// Directly manipulate the DOM element via its ref
if (inputRef.current) {
inputRef.current.focus();
inputRef.current.value = 'Focused!';
}
};
const handleIncrementStateCounter = () => {
setStateCounter(prev => prev + 1);
};
const handleLogRefCounter = () => {
// This will log the current value of the ref counter
// but won't trigger a re-render of the component itself.
alert(`Non-rendering counter (via ref): ${nonReRenderingCounter.current}`);
};
return (
<div>
<h2>useRef Examples</h2>
{/* Example 1: Accessing DOM elements */}
<h3>1. DOM Manipulation with Ref</h3>
<input type="text" ref={inputRef} placeholder="I will be focused on load" style={{ padding: '8px', marginRight: '10px' }} />
<button onClick={handleFocusClick} style={{ padding: '8px 15px' }}>Focus Input</button>
<p>Clicking 'Focus Input' will focus the input and change its value directly.</p>
<hr style={{ margin: '20px 0' }} />
{/* Example 2: Storing mutable values without re-render */}
<h3>2. Storing Mutable Values (No Re-render)</h3>
<p>State Counter (Renders UI on change): <strong>{stateCounter}</strong></p>
<button onClick={handleIncrementStateCounter} style={{ padding: '8px 15px', marginRight: '10px' }}>
Increment State Counter
</button>
<p>Clicking this button updates `stateCounter` via `useState`, triggering a UI re-render.</p>
<br />
<p>Non-Rendering Counter (Ref value, doesn't re-render UI directly): This value updates in the background every second via `useEffect` but isn't shown here because it doesn't trigger re-renders directly.</p>
<button onClick={handleLogRefCounter} style={{ padding: '8px 15px' }}>
Log Ref Counter Value
</button>
<p>Clicking 'Log Ref Counter Value' will show its current value in an alert, but the component itself won't re-render just because this value changed.</p>
<p style={{ marginTop: '10px', fontSize: '0.9em', color: '#555' }}>
<em>Check your browser's console to see the 'Timer running...' messages from `useEffect` and how `nonReRenderingCounter.current` is incrementing.</em>
</p>
</div>
);
}
export default RefExample;
```








useRef and References in React