Por que meu useEffect está rodando duas vezes? (e o fetch também)
Larissa Souza@lari_codando
Boa noite, pessoal! Estou fazendo um projeto de portfólio (uma lista de filmes consumindo uma API pública) e notei uma coisa estranha: o console.log dentro do useEffect aparece duas vezes, e na aba Network o fetch também é feito duas vezes.
useEffect(() => {
console.log('buscando filmes')
fetch('https://api.exemplo.com/filmes?pagina=' + pagina)
.then(res => res.json())
.then(dados => setFilmes(dados.resultados))
}, [pagina])
O array de dependências só tem pagina, e eu não mudo a página ao carregar. Já conferi:
- que o componente não está sendo renderizado duas vezes no App (só tem um
<ListaFilmes />) - que não existe outro
useEffectfazendo a mesma coisa - li a parte de dependências na documentação, mas não achei nada sobre isso
Uai, o que estou fazendo de errado? Isso vai acontecer em produção também? Obrigada desde já! 💛
Accepted answer
Boa noite, Lari! Você não está fazendo nada errado, uai kkkk. Isso é o React.StrictMode. Olha teu main.jsx (ou index.js): deve ter o <App /> dentro de <React.StrictMode>.
Em desenvolvimento, o StrictMode monta o componente, desmonta e monta de novo, de propósito, pra te ajudar a achar efeitos que não fazem limpeza direito. Por isso o log aparece duas vezes. Em produção (npm run build) isso NÃO acontece, roda uma vez só.
Não tira o StrictMode, ele é teu amigo. O que vale a pena é colocar a limpeza no efeito, porque se o usuário trocar de página rápido a resposta antiga pode chegar depois da nova e sobrescrever:
useEffect(() => {
const controller = new AbortController()
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(dados => setFilmes(dados.resultados))
.catch(err => {
if (err.name !== 'AbortError') console.error(err)
})
return () => controller.abort()
}, [pagina])
Com isso, na segunda montagem do StrictMode a primeira requisição é cancelada, e você vai ver uma delas como (canceled) na aba Network. Faz sentido? Qualquer coisa me chama.
Get the best of #dev_brasil weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to commentAccepted answer
Caio Nascimento@caio_backend
Boa noite, Lari! Você não está fazendo nada errado, uai kkkk. Isso é o React.StrictMode. Olha teu main.jsx (ou index.js): deve ter o <App /> dentro de <React.StrictMode>.
Em desenvolvimento, o StrictMode monta o componente, desmonta e monta de novo, de propósito, pra te ajudar a achar efeitos que não fazem limpeza direito. Por isso o log aparece duas vezes. Em produção (npm run build) isso NÃO acontece, roda uma vez só.
Não tira o StrictMode, ele é teu amigo. O que vale a pena é colocar a limpeza no efeito, porque se o usuário trocar de página rápido a resposta antiga pode chegar depois da nova e sobrescrever:
useEffect(() => {
const controller = new AbortController()
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(dados => setFilmes(dados.resultados))
.catch(err => {
if (err.name !== 'AbortError') console.error(err)
})
return () => controller.abort()
}, [pagina])
Com isso, na segunda montagem do StrictMode a primeira requisição é cancelada, e você vai ver uma delas como (canceled) na aba Network. Faz sentido? Qualquer coisa me chama.
Larissa Souza@lari_codando
Nó, Caio! Era exatamente isso, o StrictMode estava lá no main.jsx. Coloquei o AbortController e agora aparece uma requisição cancelada, do jeitinho que você falou. Muito obrigada pela paciência, de novo 💛
Thiago Valadares@thiago_pj
o caio sendo backend e respondendo pergunta de React melhor que muito front kkkk. lari, quando terminar esse projeto me manda que eu dou mais uma olhada no portfólio
Bruna Schmitt@bruna_dados
Bah, passei uma tarde inteira com isso ano passado achando que era bug meu. E tu fez a pergunta muito bem, Lari, com tudo que já tinha testado. Isso é raro!