CPCODELAB
React

useRef and DOM Refs in Depth

10 min read

Refs Beyond the Basics

useRef is more powerful than it first appears. Beyond simple DOM focus, you can use it to store previous values, track whether a component has mounted, and hold stable references to callbacks — all without triggering re-renders.

Tracking previous prop values

jsx
import { useRef, useEffect } from "react";

function PriceTracker({ price }) {
  const prevPriceRef = useRef(price);

  useEffect(() => {
    prevPriceRef.current = price;
  });

  const prev = prevPriceRef.current;
  const delta = price - prev;

  return (
    <p>
      Price: {price}
      {delta !== 0 && (
        <span style={{ color: delta > 0 ? "green" : "red" }}>
          {" "}({delta > 0 ? "+" : ""}{delta})
        </span>
      )}
    </p>
  );
}

Forwarding refs to child components

By default, a ref placed on a custom component does not reach the DOM node inside it. Use React.forwardRef to pass a ref through the component boundary so the parent can access the inner DOM element directly.

jsx
import { forwardRef, useRef } from "react";

const FancyInput = forwardRef(function FancyInput(props, ref) {
  return <input ref={ref} className="fancy-input" {...props} />;
});

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

  return (
    <>
      <FancyInput ref={inputRef} placeholder="Type here" />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}

Use useImperativeHandle alongside forwardRef to expose only a narrow API from a child — e.g., { focus, reset } — rather than the raw DOM node. This keeps the parent from reaching into internal implementation details.

Ready to test yourself?
Practice React— quiz & coding exercises