<StrictMode> é um componente do React que liga verificações extras para tudo dentro dele, só em desenvolvimento. Ele renderiza cada componente duas vezes, executa o setup, a limpeza e o setup de novo de cada efeito na montagem, executa as ref callbacks duas vezes e avisa sobre APIs descontinuadas. É por isso que o useEffect "executa duas vezes" em desenvolvimento. Em um build de produção ele não faz nada.
Você o liga envolvendo o seu app, normalmente em main.jsx:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
);
As prévias desta página rodam como um build de produção, então o StrictMode não teria efeito visível nelas. Em vez disso, cada exemplo abaixo tem o tipo de bug que o StrictMode existe para pegar e permite que você o provoque à mão. Aqui um efeito adiciona um listener de clique em document e nunca o remove. Esconda e mostre o painel algumas vezes e depois clique na página.
Cada Show adiciona mais um listener, e nenhum é removido, então um único clique registra uma vez por montagem. Esse é um vazamento que um usuário poderia causar abrindo e fechando um painel. O StrictMode o mostraria logo na primeira montagem: em desenvolvimento ele monta, desmonta e monta de novo, então você veria duas linhas de log por clique antes mesmo de tocar no botão.
Efeitos: setup, limpeza, setup
Na montagem, o StrictMode executa o seu efeito, depois a limpeza dele e depois o efeito de novo. Ele está simulando o que acontece quando um usuário sai de uma tela e volta, e conferindo se a sua limpeza desfaz o seu setup. Se desfaz, o segundo setup deixa tudo exatamente como um setup só deixaria, e você não vê nada de errado. Se não desfaz, o bug aparece na hora.
A correção do logger é uma limpeza que remove a mesma função que adicionou:
Alterne quantas vezes quiser: cada clique registra uma linha enquanto o logger está visível. Com StrictMode em desenvolvimento, o console começaria com setup, cleanup, setup, e o app continuaria se comportando corretamente. Essa sequência é o sinal de um efeito saudável, não um problema para desligar.
Efeitos comuns que precisam de limpeza: event listeners, setInterval e setTimeout, assinaturas, conexões de WebSocket ou chat e requisições cuja resposta deve ser ignorada se o componente não existir mais. A página do useEffect mostra o padrão de limpeza para cada um.
Renderizações: chamadas duas vezes
O StrictMode também chama a função do seu componente duas vezes a cada renderização (e as funções que você passa para useState, useMemo e useReducer, e o constructor, o render e o shouldComponentUpdate de classes). O React fica com o resultado de uma chamada e descarta o outro. Um componente puro retorna o mesmo JSX nas duas vezes, então nada muda.
Um componente que muda algo fora de si enquanto renderiza não é puro, e chamá-lo duas vezes faz a mudança acontecer duas vezes. Este adiciona uma entrada "rendered at" a um array que recebe como prop:
Cada nova renderização adiciona uma entrada que ninguém pediu. Aqui você só percebe depois de clicar. Com StrictMode, a primeira renderização já mostraria duas entradas novas em vez de uma. A correção é calcular durante a renderização sem mutar: const shown = [...entries, 'extra'].
O React 19 acrescenta um detalhe: durante a renderização dupla, useMemo e useCallback reutilizam o resultado da primeira chamada em vez de calculá-lo duas vezes.
Ref callbacks
Desde o React 19, o StrictMode também executa as ref callbacks duas vezes na montagem: conectar, limpar, conectar. Uma ref callback que adiciona um listener ou registra o nó em algum lugar precisa retornar uma limpeza, exatamente como um efeito:
<div
ref={(node) => {
const observer = new ResizeObserver(onResize);
observer.observe(node);
return () => observer.disconnect();
}}
/>
Avisos de APIs descontinuadas
O StrictMode avisa sobre APIs que estão saindo de cena, principalmente em componentes de classe, como os antigos ciclos de vida UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps e UNSAFE_componentWillUpdate. Algumas APIs sobre as quais ele avisava, como string refs e findDOMNode, foram removidas por completo do React 19.
Ligando em parte do app
<StrictMode> é um componente normal, então você pode envolver só parte da árvore. Isso ajuda ao adotá-lo em um app grande: comece pelas telas novas e vá ampliando.
function App() {
return (
<>
<Header />
<StrictMode>
<Sidebar />
<Content />
</StrictMode>
<Footer />
</>
);
}
Sidebar e Content (e tudo o que eles renderizam) recebem as verificações; Header e Footer não. Não há como desligá-lo para uma subárvore dentro de uma parte estrita.
Onde ele vem ligado por padrão:
- Vite: o template React envolve
<App />em<StrictMode>nomain.jsx. - Next.js: o App Router o liga por padrão;
reactStrictModeemnext.config.jso controla.
Em produção ele não faz nada
Um build de produção ignora <StrictMode>: uma renderização, uma execução de efeito, nenhum aviso. Então as chamadas duplas nunca custam nada aos seus usuários, e não há motivo para remover o wrapper antes de publicar.
Se um efeito duplo quebra algo em desenvolvimento, como uma requisição enviada duas vezes ou um evento de analytics registrado duas vezes, isso é informação. Na maioria das vezes a correção é uma limpeza (um indicador ignore para uma requisição, um disconnect para uma conexão). Para algo que realmente precisa acontecer uma vez por carregamento do app, como inicializar um SDK, execute-o fora de qualquer componente, no nível do módulo, ou proteja-o com um indicador no nível do módulo.
let didInit = false;
function App() {
useEffect(() => {
if (didInit) return;
didInit = true;
initAnalytics(); // runs once per page load, even in StrictMode
}, []);
}
Evite o contorno comum de uma ref que pula a segunda execução do efeito. Ele esconde o aviso sem corrigir a limpeza faltando, e o bug volta na primeira vez em que o componente realmente desmonta e monta de novo, como faz o logger acima.
Perguntas frequentes
O que o StrictMode do React faz?
Só em desenvolvimento, ele renderiza duas vezes cada componente dentro dele, executa o setup, a limpeza e o setup de novo de cada efeito quando o componente monta, executa as ref callbacks duas vezes do mesmo jeito e avisa sobre APIs descontinuadas. As chamadas extras expõem renderizações que não são puras e efeitos sem limpeza.
Por que meu useEffect executa duas vezes?
Porque o componente está dentro de <StrictMode> e você está rodando um build de desenvolvimento. O React o monta, simula uma desmontagem (sua limpeza executa) e o monta de novo. Se o segundo setup causa um bug, falta uma limpeza no efeito.
O StrictMode afeta a produção?
Não. Um build de produção renderiza uma vez e executa cada efeito uma vez, com ou sem <StrictMode>. Você pode deixá-lo no código.
Como desativo o StrictMode?
Remova o wrapper <StrictMode>, normalmente em main.jsx ou index.js, ou defina reactStrictMode: false em next.config.js. Corrigir a limpeza costuma ser melhor: a execução dupla está apontando para um bug que usuários reais podem encontrar.
Por que o console.log é impresso duas vezes?
O StrictMode chama a função do seu componente duas vezes por renderização em desenvolvimento. O React DevTools pode deixar acinzentados os logs da segunda chamada, ou escondê-los, nas configurações.