//
Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
// React 19: ref es solo una prop
function TextInput({ placeholder, ref }: { placeholder: string; ref?: React.Ref<HTMLInputElement> }) {
return <input placeholder={placeholder} ref={ref} />;
}
// Uso -- idéntico a antes
import { useRef } from "react";
function App() {
const inputRef = useRef<HTMLInputElement>(null);
return (
<div>
<TextInput ref={inputRef} placeholder="Escribe aquí..." />
<button onClick={() => inputRef.current?.focus()}>Enfocar</button>
</div>
);
}Cuándo usarlo: Usa este patrón para cualquier componente funcional que necesite exponer un nodo DOM o un manejador imperativo a un componente padre. Reemplaza forwardRef por completo.
// Una librería de componentes input reutilizable con soporte de ref
"use client";
import { useRef, useImperativeHandle, type Ref, type ReactNode } from "react";
// Reenvío simple de ref -- sin necesidad del wrapper forwardRef
function Input({
label,
error,
ref,
...inputProps
}: {
label: string;
error?: string;
ref?: Ref<HTMLInputElement>;
} & React.InputHTMLAttributes<HTMLInputElement>) {
return (
<div className="flex flex-col gap-1">
<label className="text-sm font-medium">{label}</label>
<input
ref={ref}
className={`border rounded p-2 ${error ? "border-red-500" : "border-gray-300"}`}
{...inputProps}
/>
{error && <span className="text-red-500 text-sm">{error}</span>}
</div>
);
}
// Manejador imperativo con ref -- tampoco necesita forwardRef
type ComboboxHandle = {
open: () => void;
close: () => void;
reset: () => void;
};
function Combobox({
options,
ref,
}: {
options: string[];
ref?: Ref<ComboboxHandle>;
}) {
const inputRef = useRef<HTMLInputElement>(null);
const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState("");
useImperativeHandle(ref, () => ({
open: () => setIsOpen(true),
close: () => setIsOpen(false),
reset: () => {
setValue("");
setIsOpen(false);
},
}));
return (
<div className="relative">
<input
ref={inputRef}
value={value}
onChange={(e) => setValue(e.target.value)}
onFocus={() => setIsOpen(true)}
/>
{isOpen && (
<ul className="absolute top-full left-0 border bg-white w-full">
{options
.filter((o) => o.toLowerCase().includes(value.toLowerCase()))
.map((option) => (
<li
key={option}
onClick={() => {
setValue(option);
setIsOpen(false);
}}
className="p-2 hover:bg-gray-100 cursor-pointer"
>
{option}
</li>
))}
</ul>
)}
</div>
);
}
// Componente padre usando ambos componentes
import { useState } from "react";
export default function RegistrationForm() {
const nameRef = useRef<HTMLInputElement>(null);
const comboRef = useRef<ComboboxHandle>(null);
function handleReset() {
nameRef.current?.focus();
comboRef.current?.reset();
}
return (
<form className="space-y-4">
<Input ref={nameRef} label="Nombre completo" placeholder="Jane Doe" />
<Combobox ref={comboRef} options={["Ingeniería", "Diseño", "Producto", "Marketing"]} />
<button type="button" onClick={handleReset}>
Reiniciar y enfocar nombre
</button>
</form>
);
}Lo que esto demuestra:
Input simple recibiendo ref como una prop regular y reenviándolo al <input> nativoCombobox usando useImperativeHandle con ref como una prop para exponer métodos personalizadosuseRef para interactuar con nodos DOM y manejadores imperativos de componentes hijoforwardRef en ningún lugarref se trata como una prop regular para componentes funcionales. React ya no lo elimina antes de pasar props al componente.forwardRef aún funciona y no se ha removido, pero está deprecado. Una versión futura de React lo eliminará. React registra una advertencia de deprecación en modo desarrollo.ref se incluye automáticamente en el tipo de props del componente cuando usas React.ComponentProps<typeof MyComponent>.ref como antes -- el ref apunta a la instancia de la clase. Este cambio solo afecta a componentes funcionales.useImperativeHandle(ref, createHandle) continúa funcionando exactamente como antes. La única diferencia es de dónde viene ref -- una prop en lugar del segundo argumento de forwardRef.Funciones de limpieza de ref (nuevas en React 19):
function MeasuredDiv({ ref }: { ref?: Ref<HTMLDivElement> }) {
return (
<div
ref={(node) => {
// Configuración
if (node) {
console.log("Montado:", node.getBoundingClientRect());
}
// Devuelve función de limpieza (nueva en React 19)
return () => {
console.log("Desmontado");
};
}}
>
Contenido medido
</div>
);
}Componente genérico con ref:
type ListProps<T> = {
items: T[];
renderItem: (item: T) => ReactNode;
ref?: Ref<HTMLUListElement>;
};
function List<T>({ items, renderItem, ref }: ListProps<T>) {
return (
<ul ref={ref}>
{items.map((item, i) => (
<li key={i}>{renderItem(item)}</li>
))}
</ul>
);
}Migración desde forwardRef:
// Antes (React 18)
const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
return <input ref={ref} {...props} />;
});
// Después (React 19)
function Input({ ref, ...props }: InputProps & { ref?: Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />;
}Ref<T> (no RefObject<T>) para el tipo de prop: ref?: React.Ref<HTMLInputElement>.React.Ref<T> es una unión de RefCallback<T>, RefObject<T>, y null. Esto cubre todos los patrones de uso de ref.ComponentProps, la prop ref se incluye automáticamente en los tipos de React 19.Ref<MyHandle> donde MyHandle es tu interfaz personalizada.forwardRef existente funciona pero registra una advertencia. Solución: Migra moviendo ref del segundo argumento de forwardRef al objeto props. Ejecuta el codemod de React: npx @react-codemod/cli forward-ref-as-prop.{...props} ahora incluye ref si el componente padre pasó uno. Solución: Desestructura ref explícitamente: const { ref, ...rest } = props.undefined, React avisará. Solución: Asegúrate de que los callbacks de ref devuelvan nada o devuelvan explícitamente una función de limpieza.ref en un componente de clase aún apunta a la instancia, no a una prop. Solución: No se necesita migración para componentes de clase.forwardRef internamente continúan funcionando. No necesitas esperar a que migren. Solución: No se requiere acción.| Enfoque | Cuándo elegirlo |
|---|---|
ref como prop (React 19) | Predeterminado para todos los componentes funcionales nuevos |
forwardRef (deprecado) | Código existente que aún no se ha migrado |
useImperativeHandle | Cuando necesites exponer una API personalizada en lugar de un nodo DOM |
| Callback ref | Cuando necesites ejecutar lógica en montaje/desmontaje del objetivo del ref |
| Comunicación basada en state | Cuando la comunicación padre-hijo debe provocar re-renderizados en lugar de llamadas imperativas |
forwardRef añadía complejidad innecesaria de wrapper y hacía las APIs de componentes más difíciles de entenderref se trata como una prop regular para componentes funcionales -- React ya no lo eliminaforwardRef aún funciona pero está deprecado y se eliminará en una versión futura// Antes (React 18)
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => {
return <input ref={ref} {...props} />;
});
// Después (React 19)
function Input({ ref, ...props }: Props & { ref?: Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />;
}useImperativeHandle(ref, createHandle) funciona exactamente como antesref viene de props en lugar del segundo argumento de forwardRefopen(), close(), reset()) a componentes padre<div ref={(node) => {
if (node) console.log("Montado:", node);
// Devuelve función de limpieza (nueva en React 19)
return () => console.log("Desmontado");
}} />Los callbacks de ref ahora pueden devolver una función de limpieza, similar a la limpieza de useEffect.
ref como antes -- el ref apunta a la instancia de la clasenpx @react-codemod/cli forward-ref-as-prop para migrar automáticamenteref del segundo argumento de forwardRef a la desestructuración de propstype ListProps<T> = {
items: T[];
renderItem: (item: T) => ReactNode;
ref?: Ref<HTMLUListElement>;
};
function List<T>({ items, renderItem, ref }: ListProps<T>) {
return (
<ul ref={ref}>
{items.map((item, i) => <li key={i}>{renderItem(item)}</li>)}
</ul>
);
}{...props} ahora incluye ref si el componente padre lo pasó, lo que puede reenviarlo sin intenciónref explícitamente: const { ref, ...rest } = propsref solo donde sea necesarioundefinedReact.Ref<T> (no RefObject<T>) para el tipo de prop: ref?: React.Ref<HTMLInputElement>React.Ref<T> es una unión de RefCallback<T>, RefObject<T>, y nullReact.ComponentProps<typeof MyComponent> incluye automáticamente ref en el tiporef manualmente cuando extiendes las props de componentesref se excluía de ComponentPropsforwardRef internamente continúan funcionando sin problemasforwardRef está deprecado pero funcionalRevisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥