DEV Community

Cover image for Understanding the useRef Hook in React
Sudhanshu Gaikwad
Sudhanshu Gaikwad

Posted on

2

Understanding the useRef Hook in React

The useRefHook 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 useStateHook 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 useRefand useStateis that updating the useRefvalue does not trigger a re-render, which can be particularly useful in certain scenarios.

  1. It does not cause re-renders when its value changes.
  2. It can be used to store mutable values.
  3. It can be used to directly access DOM elements.

Basic Syntax

const refContainer = useRef(initialValue);

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

Output

Image description

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;

Enter fullscreen mode Exit fullscreen mode

Output

Image description

When to Use useRef Instead of useState

Here are some scenarios where useRefis 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.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Cloudinary image

Optimize, customize, deliver, manage and analyze your images.

Remove background in all your web images at the same time, use outpainting to expand images with matching content, remove objects via open-set object detection and fill, recolor, crop, resize... Discover these and hundreds more ways to manage your web images and videos on a scale.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay