Урок 05

useRef с типами

useRef имеет перегруженные сигнатуры. Тип зависит от того, что ты хранишь.

DOM-элемент

import { useRef } from 'react';

function Form() {
    const inputRef = useRef<HTMLInputElement>(null);

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

Тип: RefObject<HTMLInputElement> — current равен HTMLInputElement | null.

Почему null? До монтирования DOM-элемента нет.

Использование

inputRef.current?.focus();
inputRef.current?.value;

Или после проверки:

if (inputRef.current) {
    inputRef.current.focus();
}

Разные элементы

const divRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
const formRef = useRef<HTMLFormElement>(null);
const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);

Типы соответствуют элементам:

  • HTMLDivElement
  • HTMLInputElement
  • HTMLButtonElement
  • HTMLFormElement
  • HTMLSelectElement
  • HTMLTextAreaElement
  • HTMLAnchorElement
  • HTMLImageElement
  • HTMLVideoElement
  • HTMLAudioElement
  • HTMLCanvasElement

Хранение значений

Если нужно хранить значение, не DOM-элемент:

const countRef = useRef(0);
// MutableRefObject<number>

current всегда есть и его можно менять:

countRef.current += 1;

С null инициализацией

const timerRef = useRef<number | null>(null);

Или для любого значения:

const dataRef = useRef<User | null>(null);

Тип RefObject

import type { RefObject } from 'react';

function Input({ ref }: { ref: RefObject<HTMLInputElement | null> }) {
    return <input ref={ref} />;
}

Передача ref в компонент

В React 19 ref — обычный пропс:

type InputProps = {
    ref?: Ref<HTMLInputElement>;
    placeholder?: string;
};

function Input({ ref, placeholder }: InputProps) {
    return <input ref={ref} placeholder={placeholder} />;
}

Ref<T> — union RefObject<T> | MutableRefObject<T> | RefCallback<T>.

RefCallback

<input ref={(el) => { /* el: HTMLInputElement | null */ }} />

forwardRef (устаревший)

До React 19:

const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
    return <input ref={ref} {...props} />;
});

В React 19 не нужен.

Хранение предыдущего значения

function usePrevious<T>(value: T): T | undefined {
    const ref = useRef<T>();

    useEffect(() => {
        ref.current = value;
    }, [value]);

    return ref.current;
}

Хранение таймера

const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);

ReturnType<typeof setInterval> — универсальный тип: подходит и для Node, и для браузера.

Хранение функции

const callbackRef = useRef<() => void>(null);

useEffect(() => {
    callbackRef.current = () => console.log('click');
});

Итоги

  • useRef<HTMLInputElement>(null) — для DOM
  • useRef(0) — для значения
  • current может быть null
  • RefObject<T>, MutableRefObject<T>, Ref<T>
  • React 19: ref — обычный пропс