Chapter 2 of 4

Reaching into the DOM

Attaching a ref to an element, and the small number of jobs that justify it.

Pass a ref object to an element's ref attribute and React sets current to the DOM node after the commit.

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

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}

What DOM refs are for

Refs are an escape hatch. Use them for things the declarative model genuinely cannot express.

  • Focus, selection and blur: element.focus(), element.select().
  • Scrolling: element.scrollIntoView().
  • Measuring: element.getBoundingClientRect().
  • Playing media: video.play(), audio.pause().
  • Handing a node to a canvas or charting library.

Callback refs

A ref can also be a function. React calls it with the node when it mounts and with null when it unmounts, which is useful when you need to react to the node appearing.

function Measured() {
  const [height, setHeight] = useState(0);

  const measure = useCallback((node) => {
    if (node) setHeight(node.getBoundingClientRect().height);
  }, []);

  return <div ref={measure}>Content</div>;
}

A list of refs

One ref holding a Map is easier than trying to create refs in a loop.
function Rows({ items }) {
  const rowRefs = useRef(new Map());

  function scrollTo(id) {
    rowRefs.current.get(id)?.scrollIntoView({ behavior: "smooth" });
  }

  return items.map((item) => (
    <li key={item.id} ref={(node) => {
      if (node) rowRefs.current.set(item.id, node);
      else rowRefs.current.delete(item.id);
    }}>
      {item.name}
    </li>
  ));
}