useLayoutEffect do react js
Como funciona o useLayoutEffect do React JS? Guia completo com exemplos
Você já precisou descobrir o tamanho de um elemento HTML antes de mostrar a tela ao usuário? Ou quis posicionar um menu exatamente ao lado de um botão, sem que ele aparecesse primeiro no lugar errado?
É nesse tipo de situação que o useLayoutEffect do React pode ajudar. Neste artigo, você vai aprender o que ele faz, como funciona por trás dos panos, quando utilizá-lo e qual é a diferença entre ele e o useEffect.
O que você vai aprender:
- O que é o
useLayoutEffecte para que serve. - Como medir elementos HTML usando React.
- Como evitar que um elemento apareça momentaneamente no lugar errado.
- Qual é a diferença entre
useLayoutEffecteuseEffect. - Quais erros evitar ao utilizar esse Hook.
1. O que é o useLayoutEffect?
O useLayoutEffect é um Hook do React que permite executar uma função depois que o React atualiza o DOM, mas antes que o navegador tenha a oportunidade de mostrar visualmente essa atualização na tela.
Calma! Vamos entender cada parte dessa explicação.
O que é um Hook?
Um Hook é uma função especial do React que permite utilizar recursos como estado, efeitos e outras funcionalidades dentro de componentes funcionais.
Por exemplo, o Hook useState permite guardar um valor. Já o useLayoutEffect permite executar um trabalho relacionado à atualização visual de um componente.
O que é o DOM?
DOM significa Document Object Model. Imagine que o navegador transforma o HTML em uma estrutura de elementos que podem ser encontrados, medidos e modificados.
Essa estrutura é o DOM. Com ele, podemos descobrir a altura de uma caixa, a largura de um botão ou a posição de um elemento na página.
Uma comparação simples
Imagine que você está pendurando um quadro na parede.
- Sem medir: você pendura o quadro e percebe que ele ficou torto. Depois, precisa corrigir.
- Medindo antes de mostrar o resultado: você verifica a posição e ajusta o quadro antes de deixar tudo pronto.
O useLayoutEffect é útil quando um componente precisa verificar informações visuais e corrigir sua apresentação antes que o navegador mostre a atualização.
Regra principal: utilize useLayoutEffect quando precisar ler informações do layout e, se necessário, fazer uma correção visual imediata antes da pintura da tela.
2. Para que serve o useLayoutEffect?
Esse Hook é especialmente útil quando o seu componente precisa conhecer a posição ou o tamanho de um elemento HTML para decidir como deve aparecer.
Veja duas situações práticas:
Exemplo A — Medir uma caixa
Você criou um painel que pode ter diferentes alturas. Precisa descobrir a altura real dele para ajustar outro elemento da interface.
O useLayoutEffect pode ler essa medida antes da pintura da atualização.
Exemplo B — Posicionar um menu
Você criou um menu flutuante que deve ficar ao lado de um botão. A posição depende do tamanho e da localização desse botão.
O Hook pode ajudar a medir o botão e calcular onde o menu deve ficar antes de a atualização ser exibida.
Ele também pode ser usado em situações que envolvem rolagem, dimensões de elementos e ajustes visuais que precisam acontecer antes da pintura.
Atenção: o useLayoutEffect não é necessário para qualquer tarefa que acontece depois de uma renderização. Para buscar dados, registrar eventos ou sincronizar o componente com sistemas externos, normalmente o useEffect é a primeira opção a considerar.
3. Como funciona por trás dos panos?
Para entender esse Hook, precisamos conhecer três etapas importantes do processo de atualização visual.
Etapa 1 — O React prepara a atualização
Quando o estado muda, o React executa novamente a lógica do componente para descobrir como a interface deve ficar.
Etapa 2 — O React atualiza o DOM
O React aplica as mudanças necessárias aos elementos da página. Nesse momento, o componente pode ler informações do DOM usando o useLayoutEffect.
Etapa 3 — O navegador pinta a tela
O navegador tem a oportunidade de desenhar a atualização para o usuário. O useLayoutEffect executa antes dessa pintura e pode provocar outra atualização de estado, se necessário.
Se o Hook atualizar o estado, o React processará a atualização resultante antes de permitir a pintura da tela. Isso ajuda a evitar que o usuário veja uma posição intermediária incorreta.
Imagine esta sequência:
Atualização do componente → DOM atualizado → medição do elemento → correção necessária → navegador pinta a tela.
Essa é a ideia central: medir e corrigir a apresentação antes de a atualização ser exibida.
Existe um detalhe importante: o navegador controla a pintura da tela. Não devemos imaginar que todo o funcionamento interno ocorre sempre em uma sequência rígida e idêntica em qualquer situação. O ponto essencial é que o useLayoutEffect e as atualizações síncronas que ele provoca bloqueiam a pintura até que esse trabalho seja concluído.
4. Qual é a sintaxe do useLayoutEffect?
A sintaxe básica é parecida com a do useEffect.
import { useLayoutEffect } from 'react';
useLayoutEffect(() => {
// Código executado após a atualização do DOM
// e antes da pintura da tela.
}, []);
Vamos entender cada parte:
import: importa o Hook do React.useLayoutEffect: chama o Hook.() => { ... }: é a função que será executada pelo Hook.[]: é o array de dependências. Ele controla quando o efeito precisa ser executado novamente.
O que são dependências?
Dependências são valores que o efeito utiliza e que podem mudar, como uma variável de estado ou uma propriedade recebida pelo componente.
| Forma | Quando executa |
|---|---|
useLayoutEffect(fn) |
Depois de cada renderização comprometida do componente. |
useLayoutEffect(fn, []) |
Após a montagem inicial, considerando o comportamento de desenvolvimento do Strict Mode. |
useLayoutEffect(fn, [valor]) |
Após a montagem e quando o valor da dependência muda. |
Na prática, você deve informar as dependências que o efeito utiliza. Isso ajuda o React a saber quando precisa repetir o trabalho.
Importante: em ambientes de desenvolvimento com StrictMode, o React pode executar um ciclo extra de configuração e limpeza dos efeitos para ajudar a encontrar problemas. Por isso, não dependa de o efeito executar exatamente uma única vez em todas as situações.
5. Primeiro exemplo prático: medir a altura de um elemento
Vamos criar um componente que descobre a altura de uma caixa HTML e mostra essa medida na tela.
Objetivo
O componente precisa medir a caixa depois que ela existe no DOM e antes que o navegador pinte a atualização.
Código completo
import {
useLayoutEffect,
useRef,
useState
} from 'react';
export default function CaixaMedida() {
const caixaRef = useRef(null);
const [altura, setAltura] = useState(0);
useLayoutEffect(() => {
if (!caixaRef.current) {
return;
}
const medida =
caixaRef.current.getBoundingClientRect().height;
setAltura(medida);
}, []);
return (
<div>
<div
ref={caixaRef}
style={{
padding: '20px',
background: '#dbeafe',
color: '#111827'
}}
>
Esta é a caixa que será medida.
</div>
<p>
Altura da caixa: {altura} px
</p>
</div>
);
}
Explicação das partes importantes
1. O useRef guarda uma referência ao elemento.
A variável caixaRef será conectada à caixa pelo atributo ref. Depois que o React cria o elemento no DOM, podemos acessar esse elemento por caixaRef.current.
2. O useState guarda a altura encontrada.
A variável altura guarda a medida. A função setAltura permite atualizar esse valor e fazer o React renderizar novamente o componente.
3. O getBoundingClientRect mede o elemento.
O método getBoundingClientRect() retorna informações sobre o retângulo que envolve o elemento. Sua propriedade height informa a altura em pixels CSS.
4. O useLayoutEffect realiza a medição.
O efeito consulta a caixa depois que o DOM foi atualizado. Em seguida, guarda a altura no estado.
Resultado esperado
A página mostrará uma caixa com o texto e, abaixo dela, algo parecido com:
Altura da caixa: 58 px
Exemplo ilustrativo. A altura real depende da fonte, do conteúdo, do tamanho da tela e dos estilos aplicados.
Por que funciona?
Primeiro, o React cria a caixa. Depois, o efeito acessa o elemento pelo ref, lê sua altura e atualiza o estado. Como a leitura e a atualização ocorrem no useLayoutEffect, o React pode concluir a atualização antes da pintura.
Detalhe importante: esse exemplo mede a caixa na montagem inicial. Se o conteúdo ou o tamanho da janela mudar depois, o efeito com dependências vazias não fará uma nova medição automaticamente. Para acompanhar mudanças de tamanho, considere usar ResizeObserver.
6. Segundo exemplo prático: posicionar um elemento antes da pintura
Agora vamos usar o Hook para ajustar a posição vertical de uma caixa. Imagine que ela precisa ficar centralizada em relação à área visível da janela.
Objetivo
Vamos medir a altura da caixa e calcular o espaço necessário para posicioná-la no centro da janela.
Código completo
import {
useLayoutEffect,
useRef,
useState
} from 'react';
export default function CaixaCentralizada() {
const caixaRef = useRef(null);
const [topo, setTopo] = useState(0);
useLayoutEffect(() => {
const caixa = caixaRef.current;
if (!caixa) {
return;
}
const altura =
caixa.getBoundingClientRect().height;
const novaPosicao =
Math.max(
0,
(window.innerHeight - altura) / 2
);
setTopo(novaPosicao);
}, []);
return (
<div
ref={caixaRef}
style={{
position: 'absolute',
top: `${topo}px`,
left: '20px',
right: '20px',
padding: '20px',
background: '#161b22',
color: 'white',
border: '1px solid #58a6ff',
borderRadius: '10px'
}}
>
Caixa posicionada com useLayoutEffect.
</div>
);
}
Explicação das partes importantes
window.innerHeightinforma a altura interna da janela do navegador.getBoundingClientRect().heightinforma a altura da caixa.- A expressão
(window.innerHeight - altura) / 2calcula a posição vertical necessária para centralizar a caixa. Math.max(0, ...)impede que a posição calculada seja negativa.top: `${topo}px`aplica a posição calculada em pixels.
Resultado esperado
A caixa será posicionada aproximadamente no centro vertical da janela. O efeito mede a caixa e atualiza a posição antes da pintura da atualização.
Por que funciona?
A posição depende da altura real da caixa. Como essa altura só pode ser medida depois que o elemento existe no DOM, o useLayoutEffect permite calcular a posição e atualizar o estado antes de a atualização ser pintada.
Limitação deste exemplo: a posição é calculada somente na montagem inicial. Para manter a caixa centralizada quando a janela for redimensionada, será necessário observar o redimensionamento e recalcular a posição. Em muitos projetos, usar Flexbox ou Grid com CSS é mais simples e eficiente do que calcular a posição manualmente.
7. Qual é a diferença entre useEffect e useLayoutEffect?
Os dois Hooks executam efeitos depois que o React atualiza o DOM. A principal diferença está no momento em que esses efeitos acontecem em relação à pintura da tela.
| Característica | useEffect | useLayoutEffect |
|---|---|---|
| Momento | Normalmente permite que o navegador pinte antes de executar o efeito. | Executa antes da pintura da atualização. |
| Medição visual | Pode ser tarde demais para corrigir a primeira apresentação sem um salto visual. | Útil quando a medição e a correção precisam acontecer antes da pintura. |
| Busca de dados | Normalmente é a opção apropriada entre os dois. | Geralmente desnecessário. |
| Desempenho | Em geral, não bloqueia a pintura da mesma maneira. | Pode atrasar a apresentação se executar trabalho demorado. |
Existe uma particularidade: o React pode executar um useEffect antes da pintura em determinadas situações. Portanto, não é correto afirmar que ele sempre executa depois da pintura. A diferença importante é que o useLayoutEffect foi feito para executar o trabalho antes da pintura e bloqueá-la até que esse trabalho termine.
Exemplo 1 — Buscar informações de uma API
Se você precisa buscar uma lista de produtos em um servidor, normalmente o useEffect é a escolha mais adequada. A busca não precisa bloquear a pintura inicial da página.
import { useEffect, useState } from 'react';
function Produtos() {
const [produtos, setProdutos] = useState([]);
useEffect(() => {
fetch('/api/produtos')
.then(resposta => resposta.json())
.then(dados => setProdutos(dados));
}, []);
return (
<ul>
{produtos.map(produto => (
<li key={produto.id}>
{produto.nome}
</li>
))}
</ul>
);
}
Por que usar useEffect? A página pode aparecer enquanto os produtos são carregados. Não há necessidade de bloquear a pintura apenas para iniciar a busca.
Observação: o exemplo pressupõe que a API retorna produtos com os campos id e nome. Em um aplicativo real, também é importante tratar erros e estados de carregamento.
Exemplo 2 — Medir e ajustar uma caixa
No exemplo da caixa centralizada, usamos useLayoutEffect porque a posição depende da altura real do elemento. Se a posição inicial estiver errada e só for corrigida depois da pintura, o usuário poderá perceber um movimento.
Como escolher?
Comece com useEffect. Troque para useLayoutEffect quando existir uma necessidade visual concreta de medir ou ajustar o layout antes da pintura.
8. O que é a função de limpeza?
Alguns efeitos precisam desfazer algo quando o componente deixa de existir ou quando o efeito precisa ser configurado novamente.
Para isso, você pode retornar uma função de limpeza dentro do efeito.
import { useLayoutEffect, useRef } from 'react';
function Painel() {
const painelRef = useRef(null);
useLayoutEffect(() => {
const painel = painelRef.current;
if (!painel) {
return;
}
const alturaAnterior =
painel.getBoundingClientRect().height;
return () => {
// Aqui poderia ocorrer a limpeza de um recurso.
// A variável demonstra a informação capturada.
console.log(alturaAnterior);
};
}, []);
return <div ref={painelRef}>Painel</div>;
}
Neste exemplo, a função retornada demonstra onde a limpeza aconteceria. O console.log não é uma limpeza necessária para medir a caixa; ele está ali apenas para tornar visível o momento em que a função é executada.
Em um caso real, a limpeza pode remover um evento registrado, desconectar um observador ou desfazer uma configuração feita pelo efeito. O React executa a limpeza antes de repetir o efeito e quando o componente é desmontado.
9. Erros comuns ao usar useLayoutEffect
Erro 1 — Usar o Hook para tudo
O useLayoutEffect pode atrasar a pintura. Se você utilizá-lo para tarefas que não precisam bloquear a tela, poderá deixar a interface mais lenta.
Como resolver: prefira useEffect para a maioria dos efeitos que não precisam medir ou corrigir o layout imediatamente.
Erro 2 — Esquecer o array de dependências
Se você omitir o array de dependências, o efeito será executado depois de cada renderização comprometida. Se ele atualizar o estado em toda execução, poderá provocar renderizações repetidas e até um ciclo infinito.
Como resolver: informe as dependências corretas e evite atualizar o estado sem necessidade.
// Evite atualizar o estado sem uma condição.
useLayoutEffect(() => {
setValor(valor + 1);
});
Nesse exemplo, cada execução muda o estado e provoca outra renderização, que executa o efeito novamente.
Erro 3 — Acessar o elemento antes de ele existir
Um ref pode ter o valor null, por exemplo, quando o elemento ainda não foi associado à referência ou quando já não está montado.
Como resolver: verifique se o elemento existe antes de ler suas propriedades.
const elemento = caixaRef.current;
if (!elemento) {
return;
}
const altura =
elemento.getBoundingClientRect().height;
Erro 4 — Esperar que funcione normalmente durante a renderização no servidor
O servidor pode gerar HTML sem ter um navegador ou um DOM disponível. Como o useLayoutEffect depende do ambiente do navegador para medir elementos, ele não consegue realizar esse trabalho durante a renderização no servidor.
Em aplicações que usam renderização no servidor, pense se a medição precisa acontecer apenas no cliente, se o componente pode ser renderizado depois da hidratação ou se um layout feito com CSS resolve o problema.
Erro 5 — Usar JavaScript quando CSS já resolve
Se você deseja centralizar uma caixa, organizar cartões ou alinhar elementos, Flexbox e Grid podem resolver o problema sem medições manuais.
/* Centralizar usando CSS */
.container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
Nesse caso, não é necessário usar useLayoutEffect para calcular manualmente a posição central.
10. Boas práticas para usar useLayoutEffect
- Comece com useEffect: use o Hook de layout somente quando houver uma necessidade visual real.
- Faça medições rápidas: evite cálculos pesados dentro do efeito.
- Use useRef: para acessar elementos do DOM sem precisar guardar o próprio elemento no estado.
- Declare as dependências corretas: inclua os valores reativos utilizados pelo efeito.
- Evite atualizações desnecessárias: só atualize o estado quando isso for realmente necessário.
- Prefira CSS quando possível: Flexbox, Grid e outras ferramentas de CSS podem resolver muitos problemas de posicionamento.
- Cuide da limpeza: remova observadores e eventos quando eles não forem mais necessários.
- Teste em diferentes telas: dimensões e posições mudam entre celulares e computadores.
11. Exercício prático para fixar o conhecimento
Agora é a sua vez. Vamos praticar com um pequeno desafio.
Desafio: medir a largura de um botão
Crie um componente chamado BotaoMedido que mostre um botão e exiba sua largura em pixels.
Passo 1: importe useLayoutEffect, useRef e useState.
Passo 2: crie uma referência com useRef(null).
Passo 3: conecte a referência ao botão usando o atributo ref.
Passo 4: dentro do useLayoutEffect, leia getBoundingClientRect().width.
Passo 5: guarde a largura no estado e mostre o valor em um parágrafo.
Uma pista para começar
const botaoRef = useRef(null);
const [largura, setLargura] = useState(0);
useLayoutEffect(() => {
// 1. Verifique se o botão existe.
// 2. Leia a largura do botão.
// 3. Atualize o estado.
}, []);
Objetivo: entender que o React precisa criar o elemento antes que você possa medir suas dimensões reais.
12. Resumo: o que você precisa lembrar?
useLayoutEffecté um Hook do React usado para executar efeitos depois da atualização do DOM e antes da pintura da tela.- Ele é útil para medir elementos e realizar correções visuais antes de a atualização aparecer.
useRefpermite acessar um elemento do DOM.getBoundingClientRect()informa dimensões e posição de um elemento.useStatepermite guardar a medida e atualizar a interface.useEffectcostuma ser suficiente para efeitos que não precisam bloquear a pintura.- O trabalho realizado no
useLayoutEffectdeve ser rápido para evitar atrasos visuais. - CSS pode ser uma solução melhor quando o objetivo é apenas organizar ou posicionar elementos.
13. Conclusão
O useLayoutEffect resolve um problema específico: permite que um componente leia informações visuais do DOM e faça ajustes antes de o navegador pintar a atualização.
Pense nele como uma ferramenta de medição e ajuste. Primeiro, o elemento existe no DOM. Depois, você mede suas dimensões, calcula o que precisa mudar e permite que a atualização seja mostrada.
Você não precisa usar esse Hook em todos os componentes. Na maioria das situações, comece com useEffect ou resolva o problema com CSS. Quando uma medição precisar acontecer antes da pintura para evitar um salto visual, o useLayoutEffect pode ser a escolha certa.
Torne-se um Programador Fullstack e domine o mercado digital!
Se você está aprendendo React JS e deseja continuar estudando programação, conheça este curso e avalie se o conteúdo combina com seus objetivos de aprendizado.
A proposta é considerar uma oportunidade de estudo complementar para quem deseja desenvolver seus conhecimentos em programação.
Uma opção para quem deseja estudar programação. Uma oportunidade para avaliar um curso voltado ao desenvolvimento Fullstack. Um possível complemento aos estudos práticos de React JS.
Conhecer o curso →Transparência: este artigo contém um link de afiliado. Podemos receber uma comissão se você realizar uma compra por meio desse link, sem custo adicional para você. Consulte a página do curso para verificar o conteúdo, as condições e os valores atualizados antes de decidir.
Continue praticando com pequenos componentes. Medir uma caixa, descobrir a largura de um botão e ajustar a posição de um menu são exercícios que ajudam a entender como o React trabalha com o DOM.
.png)
Comentários
Postar um comentário