DEV Community

Cover image for 🚀 React 19: Adeus forwardRef em muitos casos!
FoodieHoodie
FoodieHoodie

Posted on

🚀 React 19: Adeus forwardRef em muitos casos!

Vejamos como usar ref como prop normalmente!

Com a chegada do React 19, finalmente podemos nos despedir do incômodo forwardRef em muitos casos simples. Uma das mudanças mais sutis — porém poderosas — foi a melhoria no comportamento do ref, que agora pode ser passado como uma prop comum para componentes funcionais.

Essa mudança ajuda a deixar nosso código mais limpo e intuitivo, especialmente em bibliotecas como React Native, onde usamos ref com frequência para acessar elementos como TextInput, ScrollView, FlatList, etc.


🧠 Antes: forwardRef obrigatório

Até o React 18, se quiséssemos que um componente personalizado aceitasse ref, éramos obrigados a envolver o componente com forwardRef. Veja:

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

export const MeuInput = forwardRef<TextInput, TextInputProps>((props, ref) => {
  return <TextInput ref={ref} {...props} />
})
Enter fullscreen mode Exit fullscreen mode

No componente pai, usamos o ref normalmente:

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

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

  return (
    <View>
      <MeuInput ref={inputRef} />
      <Button title="Focar" onPress={() => inputRef.current?.focus()} />
    </View>
  )
}
Enter fullscreen mode Exit fullscreen mode

📌 Problema: você era obrigado a usar forwardRef em MeuInput, mesmo que ele fosse simples.


✅ Agora: ref como uma prop comum

Com o React 19, se o seu componente passar o ref diretamente para um elemento compatível, você não precisa mais usar forwardRef.

Veja como fica o mesmo exemplo com React 19:

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

export const MeuInput = (props: TextInputProps & { ref?: React.Ref<TextInput> }) => {
  return <TextInput {...props} />
}
Enter fullscreen mode Exit fullscreen mode

E no componente pai, nenhuma mudança:

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

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

  return (
    <View>
      <MeuInput ref={inputRef} />
      <Button title="Focar" onPress={() => inputRef.current?.focus()} />
    </View>
  )
}
Enter fullscreen mode Exit fullscreen mode

Sem forwardRef!

O React agora entende que se você passar um ref como prop e ele for encaminhado diretamente para um elemento interno (TextInput nesse caso), tudo funciona automaticamente.


🔥 E mais: ref com cleanup (React 19)

Outra melhoria sutil: callbacks de ref agora podem retornar uma função de cleanup, como os efeitos (useEffect):

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

⚠️ Limitações

Nem tudo são flores. Essa simplificação só funciona se:

  • O ref for passado diretamente para um elemento nativo ou DOM.
  • O seu componente não interceptar ou modificar o ref internamente.

Se você quiser aplicar lógica extra ao ref ou combiná-lo com outro, ainda será necessário usar forwardRef.


📦 Conclusão

O React 19 traz pequenas mudanças que, somadas, deixam o desenvolvimento mais fluido e elegante. Com essa melhoria no uso de ref, conseguimos:

  • Eliminar forwardRef de muitos componentes.
  • Reduzir boilerplate.
  • Ter código mais simples e direto.

🧩 Quando ainda é necessário usar forwardRef

Mesmo com as melhorias do React 19, o forwardRef ainda é necessário em alguns cenários mais avançados. Veja um exemplo real:

❌ Exemplo que não funciona sem forwardRef

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

export const MeuBox = (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

Nesse caso, o React não garante que o ref será passado corretamente, pois o componente não é “transparente”.

✅ Correto: usando forwardRef

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

export const MeuBox = 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

⚠️ Outros casos que ainda exigem forwardRef

Situação forwardRef necessário?
Ref é aplicado diretamente a um elemento DOM/Nativo ❌ Não
Ref é interceptado ou modificado internamente ✅ Sim
Ref precisa ser armazenado ou combinado com outro (mergeRefs) ✅ Sim
Componente precisa expor imperativamente uma API via ref ✅ Sim

Mesmo com as melhorias, o forwardRef ainda é uma ferramenta essencial em componentes mais complexos. Use o novo comportamento quando possível, mas saiba quando ainda é necessário usar o padrão tradicional.

Top comments (0)