DEV Community

Cover image for 🚀 React 19: ¡Adiós a forwardRef en muchos casos!
FoodieHoodie
FoodieHoodie

Posted on

🚀 React 19: ¡Adiós a forwardRef en muchos casos!

¡Veamos cómo usar ref como una prop normal!

Con la llegada de React 19, finalmente podemos despedirnos del molesto forwardRef en muchos casos sencillos. Uno de los cambios más sutiles —pero poderosos— fue la mejora en el comportamiento del ref, que ahora puede pasarse como una prop común a componentes funcionales.

Este cambio ayuda a que nuestro código sea más limpio e intuitivo, especialmente en librerías como React Native, donde usamos ref con frecuencia para acceder a elementos como TextInput, ScrollView, FlatList, etc.


🧠 Antes: forwardRef obligatorio

Hasta React 18, si queríamos que un componente personalizado aceptara un ref, estábamos obligados a envolver el componente con `forwardRef`. Mira:

// MiInput.tsx (antes)
import React, { forwardRef } from 'react'
import { TextInput, TextInputProps } from 'react-native'

export const MiInput = forwardRef<TextInput, TextInputProps>((props, ref) => {
  return <TextInput ref={ref} {...props} />
})

Enter fullscreen mode Exit fullscreen mode

En el componente padre, usábamos el ref normalmente:

// Padre.tsx
import React, { useRef } from 'react'
import { View, Button, TextInput } from 'react-native'
import { MiInput } from './MiInput'

export const Padre = () => {
  const inputRef = useRef<TextInput>(null)

  return (
    <View>
      <MiInput ref={inputRef} />
      <Button title="Enfocar" onPress={() => inputRef.current?.focus()} />
    </View>
  )
}

Enter fullscreen mode Exit fullscreen mode

📌 Problema: estabas obligado a usar `forwardRef en MiInput`, aunque fuera un componente simple.


✅ Ahora: ref como una prop común

Con React 19, si tu componente pasa el ref directamente a un elemento compatible, ya no necesitas usar `forwardRef`.

Mira cómo queda el mismo ejemplo con React 19:

// MiInput.tsx (React 19)
import React from 'react'
import { TextInput, TextInputProps } from 'react-native'

export const MiInput = (props: TextInputProps & { ref?: React.Ref<TextInput> }) => {
  return <TextInput {...props} />
}

Enter fullscreen mode Exit fullscreen mode

Y en el componente padre, ningún cambio:

// Padre.tsx
import React, { useRef } from 'react'
import { View, Button, TextInput } from 'react-native'
import { MiInput } from './MiInput'

export const Padre = () => {
  const inputRef = useRef<TextInput>(null)

  return (
    <View>
      <MiInput ref={inputRef} />
      <Button title="Enfocar" onPress={() => inputRef.current?.focus()} />
    </View>
  )
}

Enter fullscreen mode Exit fullscreen mode

¡Sin forwardRef! React ahora entiende que si pasas un ref como prop y este se encamina directamente a un elemento interno (TextInput en este caso), todo funciona automáticamente.


🔥 Y más: ref con cleanup (React 19)

Otra mejora sutil: los callbacks de ref ahora pueden devolver una función de cleanup (limpieza), al igual que los efectos (useEffect):

<TextInput
  ref={(node) => {
    console.log('Montado', node)
    return () => {
      console.log('Desmontado', node)
    }
  }}
/>

Enter fullscreen mode Exit fullscreen mode

⚠️ Limitaciones

No todo es color de rosa. Esta simplificación solo funciona si:

  • El ref se pasa directamente a un elemento nativo o del DOM.
  • Tu componente no intercepta ni modifica el `ref` internamente.

Si quieres aplicar lógica extra al ref o combinarlo con otro, seguirá siendo necesario usar forwardRef.


📦 Conclusión

React 19 trae pequeños cambios que, en conjunto, hacen que el desarrollo sea más fluido y elegante. Con esta mejora en el uso de ref, logramos:

  • Eliminar forwardRef de muchos componentes.
  • Reducir el boilerplate.
  • Tener un código más simple y directo.

🧩 Cuándo sigue siendo necesario usar forwardRef

Incluso con las mejoras de React 19, el forwardRef sigue siendo necesario en algunos escenarios más avanzados. Mira un ejemplo real:

❌ Ejemplo que no funciona sin forwardRef

import React from 'react'
import { View, Text, ViewProps } from 'react-native'

export const MiCaja = (props: ViewProps & { ref?: React.Ref<View> }) => {
  const { style, children, ...rest } = props

  return (
    <View ref={props.ref} style={[{ padding: 12 }, style]} {...rest}>
      <Text>{children}</Text>
    </View>
  )
}

Enter fullscreen mode Exit fullscreen mode

En este caso, React no garantiza que el ref se pase correctamente, ya que el componente no es "transparente".

✅ Correcto: usando forwardRef

import React, { forwardRef } from 'react'
import { View, Text, ViewProps } from 'react-native'

export const MiCaja = forwardRef<View, ViewProps>(({ style, children, ...rest }, ref) => {
  return (
    <View ref={ref} style={[{ padding: 12 }, style]} {...rest}>
      <Text>{children}</Text>
    </View>
  )
})

Enter fullscreen mode Exit fullscreen mode

⚠️ Otros casos que aún requieren forwardRef

Situación ¿forwardRef necesario?
El Ref se aplica directamente a un elemento DOM/Nativo ❌ No
El Ref es interceptado o modificado internamente ✅ Sí
El Ref necesita ser almacenado o combinado con otro (mergeRefs) ✅ Sí
El componente necesita exponer imperativamente una API vía `ref` ✅ Sí

A pesar de las mejoras, forwardRef sigue siendo una herramienta esencial en componentes más complejos. Usa el nuevo comportamiento siempre que sea posible, pero identifica cuándo sigue siendo necesario el patrón tradicional.

Top comments (0)