Beginner's Guide to React useRef: Understand with Clear, Practical Examples
When working on a React app, have you ever felt like you needed a way to keep track of something without React jumping in and saying, “Hey, let me re-render that for you”? That’s where useRef
comes to the rescue. It’s a super handy tool in React’s toolbox, but it’s often misunderstood or underused.
Let’s break it down in a friendly, no-nonsense way.
What Is useRef
?
At its core, useRef
is a way to store something that persists across renders. It’s like a tiny vault where React doesn’t mess with what’s inside. Here’s why it’s special:
It sticks around between renders. Unlike regular variables, the value inside a
useRef
doesn’t get reset when your component re-renders.It doesn’t trigger re-renders. Changing the value inside a
useRef
won’t make your component refresh.It gives you direct access to DOM elements. This is perfect for tasks like focusing an input field or scrolling to a specific section of the page.
If React’s useState
is like a public noticeboard where every update is announced to everyone, useRef
is like a personal notebook where you can jot things down without anyone else noticing.
What Happens If You Don’t Pass an Initial Value to useRef
?
When you call useRef()
without an initial value, React creates an object with a current
property set to undefined
:
const ref = useRef();
console.log(ref.current); // undefined
This means ref.current
is undefined until you assign something to it. This is handy when you’re not sure what the initial value should be but want to set it later, like storing a DOM element or tracking mutable data.
General Use Cases for useRef
Let’s explore some practical scenarios where useRef
shines:
1. Managing Focus or Accessing DOM Elements
Sometimes, you need to directly interact with a DOM element. useRef
makes this super easy.
Example: Focusing an Input Field
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus(); // Focus the input element
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Focus me!" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
export default FocusInput;
2. Storing Mutable Variables
When you need to keep track of values that don’t affect the UI, useRef
is your go-to. This is great for timers, counters, or storing custom data.
Example: Timer
import React, { useRef, useState } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
const timerRef = useRef(null);
const startTimer = () => {
timerRef.current = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(timerRef.current);
};
return (
<div>
<h1>Time: {seconds}s</h1>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}
export default Timer;
3. Tracking Previous Values
Sometimes, you need to remember what a value was before it changed. useRef
can help with that.
Example: Tracking Previous State
import React, { useRef, useEffect, useState } from 'react';
function PreviousValueTracker() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
}, [count]);
const prevCount = prevCountRef.current;
return (
<div>
<h1>Current Count: {count}</h1>
<h2>Previous Count: {prevCount}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default PreviousValueTracker;
4. Avoiding Re-renders with Side Effects
When dealing with side effects, such as clearing or resetting timers, useRef
ensures your logic runs smoothly without unnecessary re-renders.
What Problems Does useRef
Solve?
Unnecessary Re-renders: Unlike
useState
, updates touseRef
don’t trigger a component re-render.Performance Optimization: Ideal for storing values that don’t need to affect the UI, like tracking elapsed time or storing custom data.
Direct DOM Manipulation: Simplifies tasks like focusing inputs or interacting with scrollable containers.
When NOT to Use useRef
While useRef
is powerful, it’s not a magic wand for everything. Avoid using it in these scenarios:
UI State Management: If your value affects what’s displayed to the user, use
useState
. Updates touseRef
won’t trigger re-renders, so the UI won’t reflect changes.Complex State Logic: For intricate state relationships, stick with
useState
or a state management library like Redux.
Quick Tips for Using useRef
Effectively
Use
useRef
for values that change frequently but don’t need to update the UI.Combine it with
useEffect
for managing side effects like event listeners or timers.Avoid overusing
useRef
for things better suited to state or props.
Wrapping Up
useRef
is a powerful tool that can make your React apps more efficient and your life as a developer easier. Whether you’re managing focus, tracking values, or optimizing performance, useRef
has your back.
So go ahead, give it a try in your next project, and unlock its potential. You’ll wonder how you ever lived without it!