Understanding useRef and Refs in ReactJS (With Full Examples)

1 min read

Understanding useRef and Refs in ReactJS (With Full Examples)

When building React applications, there are situations where you may need to directly access or interact with a DOM element or store a mutable value that doesn’t trigger a re-render. This is where useRef() comes in.


What is useRef?

useRef is a hook that returns a mutable object with a .current property. It can be used for two main purposes:

  1. Accessing DOM elements (like document.querySelector)
  2. Storing persistent mutable values between renders without re-rendering

Syntax

const myRef = useRef(initialValue);
  • The current property on the object returned by useRef can be read or written.
  • React does not re-render when .current changes.

Example 1: Accessing a DOM Element

Let’s build a simple form where clicking a button will automatically focus the input field.

Code:

import React, { useRef } from 'react';

function FocusInput() {
const inputRef = useRef(null);

const handleClick = () => {
// Access the DOM node directly and focus it
inputRef.current.focus();
};

return (
<div>
<h2>Focus Input Example</h2>
<input ref={inputRef} type="text" placeholder="Click button to focus" />
<button onClick={handleClick}>Focus Input</button>
</div>
);
}

export default FocusInput;

Explanation:

  • inputRef is initialized with null.
  • ref={inputRef} binds the inputRef to the input DOM element.
  • inputRef.current gives direct access to the actual input DOM node.

Example 2: Storing Mutable Values Across Renders

Let’s say you want to count how many times a component has rendered without triggering a re-render.

Code:

import React, { useEffect, useRef, useState } from 'react';

function RenderCounter() {
  const [count, setCount] = useState(0);
  const renderCount = useRef(1);

  useEffect(() => {
    renderCount.current += 1;
  });

  return (
    <div>
      <h2>Render Counter Example</h2>
      <p>Button clicked: {count} times</p>
      <p>Component rendered: {renderCount.current} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default RenderCounter;

Explanation:

  • renderCount.current is updated every time the component re-renders.
  • Because we’re not using state, the update to renderCount doesn’t trigger another render.

Real-World Use Cases

  • Focusing inputs or scrolling into view.
  • Storing previous props or state (e.g., for comparison).
  • Avoiding useEffect race conditions.
  • Debounce timers or intervals (e.g., using setTimeout/setInterval).

useRef vs useState

FeatureuseRefuseState
Triggers re-render?NoYes
Persists between renders?YesYes
Common useDOM access, store mutable valuesState management

Gotchas

  • Updating ref.current will not trigger a re-render.
  • Don’t use useRef for dynamic values that need to trigger UI updates — use useState for that.

Conclusion

useRef is a powerful and versatile tool in React. Whether you’re managing DOM elements or keeping track of mutable values across renders, useRef can make your code cleaner and more efficient — without unnecessary re-renders.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *