Back to Flow

Refs

website/docs/react/refs.md

0.320.04.5 KB
Original Source

React allows you to grab the instance of an element or component with refs.

Refs with the useRef hook {#toc-refs-in-functional-components}

Inside a component, refs are created with the useRef hook:

js
import {useRef} from 'react';
import * as React from 'react';

component MyComponent() {
  const buttonRef = useRef<null | HTMLButtonElement>(null);
  return <button ref={buttonRef}>Toggle</button>;
}

Note that useRef wraps the ref value in an object with a current property. This must be reflected in the type of anything accepting the ref value.

The type useRef returns is React.RefObject<T>. Use it to annotate anything that accepts the ref object, such as a helper that reads current:

js
import {useRef} from 'react';
import * as React from 'react';

function focusInput(ref: React.RefObject<null | HTMLInputElement>) {
  if (ref.current != null) {
    ref.current.focus();
  }
}

component MyComponent() {
  const inputRef = useRef<null | HTMLInputElement>(null);
  return <input ref={inputRef} onClick={() => focusInput(inputRef)} />;
}

Reading ref.current {#toc-reading-ref-current}

The current property starts out null and is only populated after the element mounts, so its type includes null. Refine it with a != null check before using it:

js
import {useRef} from 'react';
import * as React from 'react';

component MyComponent() {
  const inputRef = useRef<null | HTMLInputElement>(null);

  const focusInput = () => {
    inputRef.current.focus(); // ERROR: `current` may be null
    if (inputRef.current != null) {
      inputRef.current.focus(); // OK: refined to non-null
    }
  };

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

Accepting a ref with React.RefSetter {#toc-accepting-a-ref}

To let a parent attach a ref to your component, add a ref parameter typed with React.RefSetter<T>, where T is the instance you expose. With Component Syntax this is just another parameter:

js
import {useRef} from 'react';
import * as React from 'react';

component FancyInput(ref: React.RefSetter<HTMLInputElement>) {
  return <input ref={ref} />;
}

component Form() {
  const inputRef = useRef<null | HTMLInputElement>(null);
  return <FancyInput ref={inputRef} />;
}

You write the ref parameter the same way regardless of the React version you target; behind the scenes Component Syntax compiles it to a React.forwardRef call (React 18) or a plain ref prop (React 19). The ref must be a direct parameter, not nested in a rest parameter. See Ref Parameters for the full explanation.

Callback refs {#toc-callback-refs}

Instead of a ref object, you can pass a function as a ref. React calls it with the element instance when it mounts, and with null when it unmounts, so the parameter type is T | null:

js
import * as React from 'react';

component MyComponent() {
  const setButtonRef = (button: HTMLButtonElement | null) => {
    if (button != null) {
      button.focus();
    }
  };

  return <button ref={setButtonRef}>Toggle</button>;
}

A ref parameter typed React.RefSetter<T> accepts both a ref object and a callback ref, so a component written with the pattern above works with either.

Deriving ref types {#toc-deriving-ref-types}

To name the type behind a ref without spelling it out, Flow provides two utilities:

  • React.ElementRef<typeof Component> gives the instance type a component exposes (for example HTMLInputElement for an 'input', or a class instance for a class component).
  • React.RefOf<Component> gives the type of the current field on a component's ref prop, or void if it has none.

See Also {#toc-see-also}