The useRef
Hook is an essential tool in React that allows us to store values between renders, directly access DOM elements, and avoid unnecessary re-renders. It’s often compared to the useState
Hook but serves a different purpose.
What is the
useRef
Hook?
The useRef
Hook creates a reference to a value or DOM element that persists between component renders. The key difference between useRef
and useState
is that updating the useRef
value does not trigger a re-render, which can be particularly useful in certain scenarios.
- It does not cause re-renders when its value changes.
- It can be used to store mutable values.
- It can be used to directly access DOM elements.
Basic Syntax
const refContainer = useRef(initialValue);
Example 1: Persisting Values Between Renders
import React, { useRef, useEffect } from "react";
function RenderCount() {
const renderCount = useRef(1);
useEffect(() => {
renderCount.current = renderCount.current + 1;
});
// Inline styles
const containerStyle = {
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
backgroundColor: "#f4f4f4",
};
const headingStyle = {
fontSize: "2rem",
color: "#333",
fontFamily: "Arial, sans-serif",
backgroundColor: "#fff",
padding: "20px",
borderRadius: "8px",
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.1)",
};
return (
<div style={containerStyle}>
<h1 style={headingStyle}>
This component has rendered {renderCount.current} times.
</h1>
</div>
);
}
export default RenderCount;
Output
Example 2: Accessing DOM Elements
import React, { useState, useRef } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef(null);
// Start the timer
const startTimer = () => {
if (!intervalRef.current) {
intervalRef.current = setInterval(() => {
setSeconds((prevSeconds) => prevSeconds + 1);
}, 1000);
}
};
// Stop the timer
const stopTimer = () => {
clearInterval(intervalRef.current);
intervalRef.current = null;
};
// Reset the timer
const resetTimer = () => {
stopTimer();
setSeconds(0);
};
// Inline styles
const timerContainerStyle = {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
height: "100vh",
backgroundColor: "#f0f2f5", // Light neutral background
};
const timerDisplayStyle = {
fontSize: "3rem",
color: "#2c3e50", // Dark blue-gray for a professional look
};
const buttonStyle = {
padding: "10px 20px",
margin: "10px",
fontSize: "1rem",
backgroundColor: "#2980b9", // Professional blue
color: "white",
border: "none",
borderRadius: "5px",
cursor: "pointer",
transition: "background-color 0.3s ease-in-out",
};
const buttonHoverStyle = {
backgroundColor: "#1a5276", // Darker shade for hover effect
};
return (
<div style={timerContainerStyle}>
<h1 style={timerDisplayStyle}>{seconds} seconds</h1>
<div>
<button
style={buttonStyle}
onClick={startTimer}
onMouseOver={(e) => (e.currentTarget.style.backgroundColor = buttonHoverStyle.backgroundColor)}
onMouseOut={(e) => (e.currentTarget.style.backgroundColor = buttonStyle.backgroundColor)}
>
Start
</button>
<button
style={buttonStyle}
onClick={stopTimer}
onMouseOver={(e) => (e.currentTarget.style.backgroundColor = buttonHoverStyle.backgroundColor)}
onMouseOut={(e) => (e.currentTarget.style.backgroundColor = buttonStyle.backgroundColor)}
>
Stop
</button>
<button
style={buttonStyle}
onClick={resetTimer}
onMouseOver={(e) => (e.currentTarget.style.backgroundColor = buttonHoverStyle.backgroundColor)}
onMouseOut={(e) => (e.currentTarget.style.backgroundColor = buttonStyle.backgroundColor)}
>
Reset
</button>
</div>
</div>
);
}
export default Timer;
Output
When to Use
useRef
Instead ofuseState
Here are some scenarios where useRef
is more appropriate than useState
:
When you need to store a value that doesn’t need to trigger a re-render when updated (e.g., timers, counters, or tracking renders).
When you need to directly access or modify DOM elements without causing a re-render.
Top comments (0)