Chapter 3 of 4

Forwarding Refs

Letting a parent reach the DOM node inside your component.

A ref placed on your own component does not reach the DOM, because ref is not a normal prop. forwardRef passes it through to the element you choose.

import { forwardRef, useRef } from "react";

const TextField = forwardRef(function TextField({ label, ...rest }, ref) {
  return (
    <label>
      {label}
      <input ref={ref} {...rest} />
    </label>
  );
});

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

  return (
    <form onSubmit={() => emailRef.current.focus()}>
      <TextField ref={emailRef} label="Email" />
    </form>
  );
}

Exposing a limited API with useImperativeHandle

Sometimes you want the parent to call specific methods rather than get the raw node. useImperativeHandle lets you decide what ref.current contains.

const VideoPlayer = forwardRef(function VideoPlayer(props, ref) {
  const videoRef = useRef(null);

  useImperativeHandle(ref, () => ({
    play: () => videoRef.current.play(),
    pause: () => videoRef.current.pause(),
  }), []);

  return <video ref={videoRef} src={props.src} />;
});

// The parent gets play and pause, and nothing else
playerRef.current.play();

Build a small mutable box

Write createRef so it returns an object with a current property initialised to the given value, and so assigning to current works.