The useRef Hook is used to create a mutable reference that persists between renders. It is commonly used to access DOM elements directly, store values that should persist without causing a re-render, and work with timers or other external values.
useRef is a React Hook that creates a mutable reference
object.
import { useRef } from "react";
function App() {
const myRef = useRef();
return (
<h1>
Hello React
</h1>
);
}
The reference can be accessed using the current property.
The Hook is imported from React.
import { useRef } from "react";
It can also be imported together with other Hooks.
import {
useState,
useRef
} from "react";
The basic syntax is:
const reference = useRef(initialValue);
For example:
const countRef = useRef(0);
The value is available through countRef.current.
The object returned by useRef has a
current property.
const nameRef = useRef("Rahul");
console.log(nameRef.current);
The current value can be read or changed through
.current.
One of the most common uses of useRef is accessing a DOM
element.
const inputRef = useRef();
<input ref={inputRef} />
React assigns the corresponding DOM element to
inputRef.current.
A ref can be used to focus an input programmatically.
import { useRef } from "react";
function App() {
const inputRef = useRef();
function focusInput() {
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>
Focus Input
</button>
</div>
);
}
export default App;
React normally handles the UI declaratively. However, some operations such as focusing an input require access to the actual DOM element.
A ref provides a way to access that DOM node when necessary.
inputRef.current.focus();
A ref can be used to select text inside an input.
function selectText() {
inputRef.current.select();
}
The select() method is available on suitable input
elements.
Changing the current property of a ref does not cause the
component to render again.
const countRef = useRef(0);
function increase() {
countRef.current =
countRef.current + 1;
}
The ref value changes, but React does not re-render simply because the ref changed.
| useState | useRef |
|---|---|
| Stores state used for rendering. | Stores a mutable reference. |
| Updating state causes a re-render. | Changing current does not cause a re-render. |
| Useful for UI state. | Useful for DOM references and persistent values. |
A ref can be used to keep a value between renders.
const previousValue = useRef();
previousValue.current = value;
This technique can be useful when a component needs to remember a value without using that value itself to trigger another render.
Refs are often used together with useEffect.
import {
useRef,
useEffect
} from "react";
function App() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<input ref={inputRef} />
);
}
The effect focuses the input after the component has been rendered.
A common example is automatically focusing an input when a component loads.
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
A ref can be attached to different DOM elements, including buttons.
const buttonRef = useRef();
<button ref={buttonRef}>
Click Me
</button>
The DOM element can then be accessed with:
buttonRef.current
A DOM reference can be used for certain imperative DOM operations.
const inputRef = useRef();
function disableInput() {
inputRef.current.disabled = true;
}
<input ref={inputRef} />
<button onClick={disableInput}>
Disable
</button>
In normal React applications, prefer state-driven UI when the change can be expressed declaratively.
Refs can store values such as timer IDs that need to persist between renders without causing re-renders.
const timerRef = useRef(null);
timerRef.current = setInterval(() => {
console.log("Running");
}, 1000);
const timerRef = useRef(null);
function startTimer() {
timerRef.current = setInterval(() => {
console.log("Running");
}, 1000);
}
function stopTimer() {
clearInterval(timerRef.current);
}
The ref keeps the timer ID available between renders.
A timeout ID can also be stored in a ref.
const timeoutRef = useRef(null);
function startTimeout() {
timeoutRef.current = setTimeout(() => {
console.log("Completed");
}, 2000);
}
function cancelTimeout() {
clearTimeout(timeoutRef.current);
}
A ref can remember the previous value of state between renders.
const [count, setCount] = useState(0);
const previousCount = useRef();
useEffect(() => {
previousCount.current = count;
}, [count]);
The ref can preserve the value between renders.
A ref can be used to focus an input when validation fails.
const inputRef = useRef();
function validate() {
if (name.trim() === "") {
inputRef.current.focus();
}
}
<input
ref={inputRef}
value={name}
onChange={(e) =>
setName(e.target.value)
}
/>
A DOM reference can be used to read information about an element.
const boxRef = useRef();
function showSize() {
const width =
boxRef.current.offsetWidth;
console.log(width);
}
<div ref={boxRef}>
Content
</div>
This can be useful when an application needs information about the rendered DOM element.
A ref can provide access to media elements such as
<video>.
const videoRef = useRef();
function playVideo() {
videoRef.current.play();
}
<video ref={videoRef} controls>
Your browser does not support video.
</video>
<button onClick={playVideo}>
Play
</button>
Refs can also provide access to elements such as
<canvas>.
const canvasRef = useRef();
useEffect(() => {
const canvas =
canvasRef.current;
const context =
canvas.getContext("2d");
}, []);
return (
<canvas ref={canvasRef} />
);
Some third-party JavaScript libraries need direct access to DOM elements. A ref can provide the required DOM element.
const containerRef = useRef();
useEffect(() => {
const element =
containerRef.current;
// Initialize library here
}, []);
return (
<div ref={containerRef}>
</div>
);
The ref object remains available across renders of the same component instance.
const renderCount = useRef(0);
renderCount.current++;
console.log(
renderCount.current
);
The ref value can persist without being state that triggers rendering.
If changing a value should update the visible interface, state is usually the appropriate choice.
Prefer:
const [count, setCount] = useState(0);
setCount(count + 1);
Instead of using a ref for a value that needs to be rendered.
const countRef = useRef(0);
countRef.current++;
| useState | useRef |
|---|---|
| Used for state that affects rendering. | Used for persistent mutable references. |
| Updating state causes a re-render. | Updating current does not cause a re-render. |
| Useful for displaying changing values. | Useful for DOM references and values that do not need rendering. |
import {
useRef,
useEffect
} from "react";
function App() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
function focusInput() {
inputRef.current.focus();
}
return (
<div>
<h1>
useRef Example
</h1>
<input
ref={inputRef}
placeholder="Enter your name"
/>
<button onClick={focusInput}>
Focus Input
</button>
</div>
);
}
export default App;
useRef.ref attribute.current before the DOM element exists.useRef when you need a persistent mutable value.ref={myRef} to connect a ref to a DOM element.myRef.current.current does not trigger a re-render.useRef creates a persistent mutable reference..current.useRef can work together with useEffect.
Question: What is one important feature of the
useRef Hook?