Sometimes React isn’t enough on its own — you need direct access to the DOM. This usually happens when: integrating a DOM-based library, focusing an input…
useRefuseRef gives you a persistent object whose .current points to a DOM element.
import { useEffect, useRef } from "react";export default function Chart() {const containerRef = useRef(null);useEffect(() => {const chart = createChart(containerRef.current);return () => chart.destroy();}, []);return <div ref={containerRef} />;}
useRefReact is built around state → UI. When you use useRef to manually change the DOM, React doesn’t know about it.
inputRef.current.value = "Hello";
State changes are visible in React DevTools. Ref changes are not. That means:
In React, dependency arrays work best with primitive values like: strings, numbers, booleans. These values are compared by value, which makes them stable and predictable.
Primitive dependencies are safe because they don’t change unless their actual value changes.
For primitives, that means:
1 === 1 // true"hi" === "hi" // truetrue === true // true
So React can reliably tell whether something changed.
const userId = user.id;useEffect(() => {fetchUser(userId);}, [userId]);