Understanding useRef in React: What It Is and Why It’s Useful
React’s useRef
is one of those hooks that seems simple at first, but its power becomes more apparent the more you use it. It allows you to persist values across renders without causing re-renders and gives you a way to directly reference DOM elements.
What is useRef
?
useRef
is a hook that returns a mutable object with a single property: .current
.
This object remains the same between renders — React does not reset it.
Syntax:
const refContainer = useRef(initialValue);
-
refContainer.current
is initialized toinitialValue
. - The object persists for the lifetime of the component.
Key Use Cases
-
Accessing DOM elements directly
Sometimes you need to manipulate an element without triggering a re-render, like focusing an input. -
Storing values that don’t trigger re-renders
Unlike state (useState
), updating.current
does not cause the component to render again. -
Storing previous values
You can keep track of a value from the previous render.
Example 1: Accessing DOM Elements
import React, { useRef } from 'react';
export default function App() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Click button to focus me" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
What happens?
-
inputRef
stores a reference to the<input>
DOM element. - Calling
inputRef.current.focus()
sets focus without re-rendering.
Example 2: Storing Values Without Re-render
import React, { useRef, useState } from 'react';
export default function App() {
const [count, setCount] = useState(0);
const renderCount = useRef(0);
renderCount.current += 1;
return (
<div>
<p>Count: {count}</p>
<p>Render Count: {renderCount.current}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
What happens?
-
renderCount.current
persists across renders. - Updating
renderCount.current
doesn’t trigger a re-render.
Example 3: Tracking Previous State
import React, { useState, useRef, useEffect } from 'react';
export default function App() {
const [count, setCount] = useState(0);
const prevCount = useRef();
useEffect(() => {
prevCount.current = count;
}, [count]);
return (
<div>
<p>Now: {count}, before: {prevCount.current}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
What happens?
-
prevCount.current
stores the previous value ofcount
. - It updates after each render in
useEffect
.
Key Takeaways
-
useRef
does not cause re-renders when.current
changes. - Perfect for DOM access, storing non-reactive values, or caching previous data.
- Works like an instance variable in class components.