Deprecated

Em React 19, forwardRef não é mais necessário. Passe ref como uma prop em vez disso.

forwardRef será descontinuado em uma versão futura. Saiba mais aqui.

forwardRef permite que seu componente exponha um nó do DOM ao componente pai com um ref.

const SomeComponent = forwardRef(render)

Referência

forwardRef(render)

Chame forwardRef() para permitir que seu componente receba um ref e o encaminhe para um componente filho:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});

Veja mais exemplos abaixo.

Parâmetros

  • render: A função de renderização para o seu componente. React chama esta função com as props e ref que seu componente recebeu de seu pai. O JSX que você retornar será a saída do seu componente.

Retorna

forwardRef retorna um componente React que você pode renderizar em JSX. Diferente dos componentes React definidos como funções simples, um componente retornado por forwardRef também é capaz de receber uma prop ref.

Ressalvas

  • No Modo Estrito, React chama sua função de renderização duas vezes para ajudá-lo a encontrar impurezas acidentais. Este é um comportamento apenas para desenvolvimento e não afeta a produção. Se sua função de renderização for pura (como deveria ser), isso não deve afetar a lógica do seu componente. O resultado de uma das chamadas será ignorado.

Função render

forwardRef aceita uma função de renderização como um argumento. React chama essa função com props e ref:

const MyInput = forwardRef(function MyInput(props, ref) {
return (
<label>
{props.label}
<input ref={ref} />
</label>
);
});

Parâmetros

  • props: As props passadas pelo componente pai.

  • ref: O atributo ref passado pelo componente pai. O ref pode ser um objeto ou uma função. Se o componente pai não tiver passado um ref, ele será null. Você deve passar o ref que você recebe para outro componente, ou passá-lo para useImperativeHandle.

Retorna

forwardRef retorna um componente React que você pode renderizar em JSX. Diferente dos componentes React definidos como funções simples, o componente retornado por forwardRef é capaz de receber uma prop ref.


Uso

Expondo um nó do DOM para o componente pai

Por padrão, os nós do DOM de cada componente são privados. No entanto, às vezes é útil expor um nó do DOM para o pai - por exemplo, para permitir focar nele. Para participar, envolva a definição do seu componente em forwardRef():

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} />
</label>
);
});

Você receberá um ref como o segundo argumento após as props. Passe-o para o nó do DOM que você deseja expor:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});

Isso permite que o componente Form pai acesse o nó do DOM </input> exposto por MyInput:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

Este componente Form passa um ref para MyInput. O componente MyInput encaminha aquele ref para a tag do navegador <input>. Como resultado, o componente Form pode acessar aquele nó do DOM <input> e chamar focus() nele.

Tenha em mente que expor um ref para o nó do DOM dentro do seu componente torna mais difícil alterar o funcionamento interno do seu componente mais tarde. Você tipicamente expõe nós do DOM de componentes reutilizáveis de baixo nível como botões ou entradas de texto, mas você não fará isso para componentes em nível de aplicação como um avatar ou um comentário.

Exemplos de encaminhamento de um ref

Example 1 of 2:
Focando uma entrada de texto

Clicar no botão irá focar a entrada. O componente Form define um ref e o passa para o componente MyInput. O componente MyInput encaminha aquele ref para o <input> do navegador. Isso permite que o componente Form foque o <input>.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


Encaminhando um ref através de múltiplos componentes

Em vez de encaminhar um ref para um nó do DOM, você pode encaminhá-lo para seu próprio componente como MyInput:

const FormField = forwardRef(function FormField(props, ref) {
// ...
return (
<>
<MyInput ref={ref} />
...
</>
);
});

Se aquele componente MyInput encaminhar um ref para seu <input>, um ref para FormField lhe dará aquele <input>:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<FormField label="Enter your name:" ref={ref} isRequired={true} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

O componente Form define um ref e o passa para FormField. O componente FormField encaminha aquele ref para MyInput, que o encaminha para um nó do DOM <input> do navegador. É assim que Form acessa aquele nó do DOM.

import { useRef } from 'react';
import FormField from './FormField.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <FormField label="Enter your name:" ref={ref} isRequired={true} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


Expondo um manipulador imperativo em vez de um nó do DOM

Em vez de expor um nó do DOM inteiro, você pode expor um objeto customizado, chamado manipulador imperativo, com um conjunto mais restrito de métodos. Para fazer isso, você precisaria definir um ref separado para manter o nó do DOM:

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

// ...

return <input {...props} ref={inputRef} />;
});

Passe o ref que você recebeu para useImperativeHandle e especifique o valor que você deseja expor para o ref:

import { forwardRef, useRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);

return <input {...props} ref={inputRef} />;
});

Se algum componente receber um ref para MyInput, ele só receberá seu objeto { focus, scrollIntoView } em vez do nó do DOM. Isso permite que você limite a informação que você expõe sobre o seu nó do DOM ao mínimo.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
    // Isso não vai funcionar porque o nó do DOM não está exposto:
    // ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

Leia mais sobre o uso de manipuladores imperativos.

Pitfall

Não use demais refs. Você deve usar refs apenas para comportamentos imperativos que você não pode expressar como props: por exemplo, rolar para um nó, focar em um nó, acionar uma animação, selecionar texto, e assim por diante.

Se você pode expressar algo como uma prop, você não deve usar um ref. Por exemplo, em vez de expor um manipulador imperativo como { open, close } de um componente Modal, é melhor usar isOpen como uma prop como <Modal isOpen={isOpen} />. Effects pode ajudá-lo a expor comportamentos imperativos via props.


Solução de problemas

Meu componente está encapsulado em forwardRef, mas o ref para ele é sempre null

Isso geralmente significa que você esqueceu de realmente usar o ref que você recebeu.

Por exemplo, este componente não faz nada com o seu ref:

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input />
</label>
);
});

Para corrigi-lo, passe o ref para um nó do DOM ou outro componente que pode aceitar um ref:

const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input ref={ref} />
</label>
);
});

O ref para MyInput também pode ser null se alguma lógica for condicional:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
{showInput && <input ref={ref} />}
</label>
);
});

Se showInput for false, então o ref não será encaminhado para nenhum nó, e um ref para MyInput permanecerá vazio. Isso é particularmente fácil de perder se a condição estiver escondida dentro de outro componente, como Panel neste exemplo:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
<Panel isExpanded={showInput}>
<input ref={ref} />
</Panel>
</label>
);
});