useRef
useRef
é um Hook React que permite que você referencie um valor que não é necessário para renderização.
const ref = useRef(initialValue)
Referência
useRef(initialValue)
Chame useRef
no topo do seu componente para declarar uma ref.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...
Parâmetros
initialValue
: O valor que você quer que a propriedadecurrent
do objeto ref tenha inicialmente. Pode ser um valor de qualquer tipo. Este argumento é ignorado após a renderização inicial.
Retorna
useRef
retorna um objeto com uma única propriedade:
current
: Inicialmente, é definido para oinitialValue
que você passou. Você pode, mais tarde, definir para outra coisa. Se você passar o objeto ref para o React como um atributoref
para um nó JSX, o React definirá sua propriedadecurrent
.
Nas próximas renderizações, useRef
retornará o mesmo objeto.
Ressalvas
- Você pode mutar a propriedade
ref.current
. Diferente do state, é mutável. No entanto, se ele contiver um objeto que é usado para renderização (por exemplo, uma parte do seu state), então você não deve mutar esse objeto. - Quando você muda a propriedade
ref.current
, o React não re-renderiza o seu componente. O React não está ciente quando você o muda porque uma ref é um objeto JavaScript simples. - Não escreva ou leia
ref.current
durante a renderização, exceto para inicialização. Isso torna o comportamento do seu componente imprevisível. - No Strict Mode, o React irá chamar a função do seu componente duas vezes para ajudar você a encontrar impurezas acidentais. Esse é um comportamento apenas para desenvolvimento e não afeta a produção. Cada objeto ref será criado duas vezes, mas uma das versões será descartada. Se a função do seu componente é pura (como deveria ser), isso não deve afetar o comportamento.
Uso
Referenciando um valor com uma ref
Chame useRef
no nível mais alto do seu componente para declarar um ou mais refs.
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0);
// ...
useRef
retorna um objeto ref com uma única propriedade current
inicialmente definida para o valor inicial que você forneceu.
Nas renderizações seguintes, useRef
retornará o mesmo objeto. Você pode mudar sua propriedade current
para armazenar informações e lê-las depois. Isso pode fazer você lembrar do state, mas há uma diferença importante.
Mudar uma ref não dispara uma re-renderização. Isso significa que as refs são perfeitas para armazenar informações que não afetam a saída visual do seu componente. Por exemplo, se você precisar armazenar um ID de intervalo e recuperá-lo depois, você pode colocá-lo em uma ref. Para atualizar o valor dentro da ref, você precisa mudar manualmente sua propriedade current
:
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}
Mais tarde, você pode ler o ID do intervalo da ref para que possa chamar clear o intervalo:
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}
Ao usar uma ref, você garante que:
- Você pode armazenar informações entre as re-renderizações (diferente das variáveis normais, que reiniciam em cada renderização).
- Mudá-la não dispara uma re-renderização (diferente das variáveis do state, que disparam uma re-renderização).
- A informação é local para cada cópia do seu componente (diferente das variáveis externas, que são compartilhadas).
Mudar uma ref não dispara uma re-renderização, então refs não são apropriadas para armazenar informações que você quer exibir na tela. Use state para isso. Leia mais sobre escolher entre useRef
e useState
.
Example 1 of 2: Contador de cliques
Este componente usa uma ref para controlar quantas vezes o botão foi clicado. Note que é aceitável usar uma ref em vez de state aqui porque a contagem de cliques é somente lida e escrita em um manipulador de evento.
import { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked ' + ref.current + ' times!'); } return ( <button onClick={handleClick}> Click me! </button> ); }
Se você mostrar {ref.current}
no JSX, o número não irá atualizar no clique. Isso ocorre porque definir ref.current
não dispara uma re-renderização. Informações que são usadas para renderização deveriam ser state, em vez disso.
Manipulando o DOM com uma ref
É particularmente comum usar uma ref para manipular o DOM. O React tem suporte embutido para isso.
Primeiramente, declare um objeto ref com um valor inicial de null
:
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...
Então passe o seu objeto ref como o atributo ref
para o JSX do nó do DOM que você quer manipular:
// ...
return <input ref={inputRef} />;
Depois que o React cria o nó do DOM e o coloca na tela, o React irá definir a propriedade current
do seu objeto ref para esse nó do DOM. Agora você pode acessar o nó DOM do <input>
e chamar métodos como focus()
:
function handleClick() {
inputRef.current.focus();
}
O React irá definir a propriedade current
de volta para null
quando o nó for removido da tela.
Leia mais sobre manipular o DOM com refs.
Example 1 of 4: Focando uma entrada de texto
Neste exemplo, clicar no botão irá focar no input:
import { useRef } from 'react'; export default function Form() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <input ref={inputRef} /> <button onClick={handleClick}> Focus the input </button> </> ); }
Evitando recriar o conteúdo da ref
O React salva o valor inicial do ref uma vez e o ignora nas renderizações seguintes.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...
Embora o resultado de new VideoPlayer()
seja usado somente para a renderização inicial, você ainda está chamando essa função em cada renderização. Isso pode ser um desperdício se estiver criando objetos caros.
Para resolver isso, você pode inicializar a ref assim, em vez disso:
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...
Normalmente, escrever ou ler ref.current
durante a renderização não é permitido. No entanto, é aceitável neste caso porque o resultado é sempre o mesmo, e a condição só executa durante a inicialização, então é totalmente previsível.
Deep Dive
Se você usa um type checker e não quer sempre verificar por null
, você pode tentar um padrão como este, em vez disso:
function Video() {
const playerRef = useRef(null);
function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}
// ...
Aqui, a própria playerRef
é nulável. No entanto, você deve ser capaz de convencer seu type checker de que não há caso em que getPlayer()
retorne null
. Então use getPlayer()
em seus manipuladores de eventos.
Solução de Problemas
Eu não consigo obter uma ref para um componente customizado
Se você tentar passar uma ref
para o seu próprio componente assim:
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
Você pode obter um erro no console:
Por padrão, seus próprios componentes não expõem refs para os nós do DOM dentro deles.
Para corrigir isso, encontre o componente para o qual você quer obter uma ref:
export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}
E então adicione ref
para a lista de props que seu componente aceita e passe ref
como uma prop para o componente embutido relevante como este:
function MyInput({ value, onChange, ref }) {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
};
export default MyInput;
Então o componente pai pode obter uma ref para ele.
Leia mais sobre acessar nós DOM de outro componente.