Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як у React 19 передати ref у власний компонент без forwardRef і як типізувати обгортку над нативним елементом?

До React 19 функціональний компонент не отримував ref як prop - для цього обгортали компонент у forwardRef:

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

У React 19 ref - звичайний prop:

import type { ComponentProps } from 'react';

type InputProps = ComponentProps<'input'> & {
  label: string;
};

function Input({ label, ref, ...props }: InputProps) {
  return (
    <label>
      {label}
      <input ref={ref} {...props} />
    </label>
  );
}
const emailRef = useRef<HTMLInputElement>(null);
<Input label="Email" type="email" ref={emailRef} required />;

forwardRef ще працює, але документація позначає його як непотрібний для нового коду, і в майбутніх версіях його оголосять застарілим.

ComponentProps<'input'> - усі атрибути нативного <input>, включно з ref, обробниками подій, aria-* і data-*. Обгортка автоматично приймає все, що приймає нативний елемент, без ручного перелічення.

Варіанти утилітних типів:

  • ComponentProps<'button'> - атрибути разом з ref (у React 19 для нативних елементів);
  • ComponentPropsWithoutRef<'button'> - те саме без ref, коли обгортка свідомо не передає ref далі;
  • ComponentProps<typeof Button> - props іншого компонента. Корисно, щоб розширити чужий компонент чи переиспользувати його типи без експорту.

Перевизначення атрибута: якщо власний prop збігається з нативним, але має інший тип, нативний треба прибрати:

type SelectProps = Omit<ComponentProps<'select'>, 'onChange'> & {
  onChange: (value: string) => void;
};

Без Omit типи перетнуться, і TypeScript вимагатиме обробник, сумісний з обома сигнатурами одночасно.

Пастки:

  • розгорнути ...props до свого className - і переданий ззовні клас перезапише внутрішній. Порядок і злиття класів (clsx, tailwind-merge) треба продумати;
  • бібліотеки, що підтримують React 18, досі використовують forwardRef, і це нормально - для них потрібна сумісність з обома версіями.

Докладніше в документації: forwardRef

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання