Refs, useRef & forwardRef

5 questions found

What is a ref in React and what is it used for?

Beginner
A ref gives you a way to directly access an actual DOM element or to store a value that does not need to cause a re render when it changes. Common uses include focusing an input field, measuring an element's size, or keeping track of a value between renders without triggering an update.
function TextInput() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleFocus}>Focus the input</button>
    </>
  );
}
Real-world example A search page automatically focuses its search input the moment a user clicks a search icon, using a ref to directly call the focus method on the actual input element.

Common follow-ups: Why does changing a ref's value not cause a component to re render?;Can you use a ref to store something other than a DOM element?

Effects & Lifecycle;Forms: Controlled & Uncontrolled Components

How is useRef different from useState when it comes to storing a value?

Intermediate
Updating a value with useState causes the component to re render so the screen reflects the new value. Updating a ref's value using useRef does not cause any re render at all, making it useful for values you need to remember between renders but that should never directly affect what is shown on screen, like tracking a previous value or a timer id.
function Timer() {
  const intervalRef = useRef(null);
  const [seconds, setSeconds] = useState(0);

  function startTimer() {
    intervalRef.current = setInterval(() => setSeconds((s) => s + 1), 1000);
  }

  function stopTimer() {
    clearInterval(intervalRef.current);
  }

  return <button onClick={startTimer}>Start</button>;
}
Real-world example A stopwatch component stores its timer id using useRef, since the id itself never needs to appear on screen, while the actual elapsed seconds are stored using useState so the display updates correctly.

Common follow-ups: What would happen if you stored the timer id using useState instead of useRef?;When would you actually want changing a value to trigger a re render versus not?

Effects & Lifecycle;Hooks

What is forwardRef and why is it needed when passing a ref to a custom component?

Advanced
By default, a ref you attach to a custom component does not automatically reach the actual DOM element inside it, since refs only work directly on native HTML elements like input or div. forwardRef lets a custom component accept a ref as a second argument and manually pass it down to the specific inner element you want the parent to actually control.
const CustomInput = React.forwardRef(function CustomInput(props, ref) {
  return <input ref={ref} {...props} />;
});

function Form() {
  const inputRef = useRef(null);
  return (
    <>
      <CustomInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
    </>
  );
}
Real-world example A shared design system component wraps a plain input with extra styling, and uses forwardRef so any page using it can still directly focus the actual input element from outside, exactly as if it were a native input.

Common follow-ups: What happens if you try to pass a ref to a custom component that does not use forwardRef?;How does forwardRef work together with the useImperativeHandle hook?

Component Composition & Children Props;Forms: Controlled & Uncontrolled Components

How would you use a ref to keep track of a component's previous prop value?

Intermediate
You can store the current prop value inside a ref after each render, using useEffect, so that the next time the component renders, the ref still holds the value from before the update. This lets you compare the current and previous values whenever you need to.
function PriceDisplay({ price }) {
  const previousPrice = useRef(price);

  useEffect(() => {
    previousPrice.current = price;
  }, [price]);

  const wentUp = price > previousPrice.current;
  return <p style={{ color: wentUp ? 'red' : 'green' }}>${price}</p>;
}
Real-world example A stock price ticker shows the price in red when it goes up and green when it goes down, by comparing the current price against the previous price stored in a ref from the last render.

Common follow-ups: Why can you not simply compare the current prop against a regular variable declared inside the component?;How would you achieve similar previous value tracking using a custom hook?

Custom Hooks;Effects & Lifecycle

What is the difference between a ref created with useRef and one created with createRef?

Beginner
useRef is meant for function components and keeps the same ref object across every render, which is almost always what you want. createRef is the older approach used inside class components, and it creates a brand new ref object every single render if called incorrectly, so it should not normally be used inside function components.
// Correct, function component, useRef keeps the same ref across renders
function MyComponent() {
  const myRef = useRef(null);
}

// Correct usage, class component, createRef called once in the constructor
class MyClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
}
Real-world example A team maintaining an older class based component correctly uses createRef inside the constructor, while all their newer function components consistently use useRef instead.

Common follow-ups: What mistake happens if createRef is accidentally called during every render instead of just once?;Is there ever a good reason to use createRef inside a modern function component?

Class Components & Legacy Lifecycle Methods;Hooks