Back

Busca de Dados no Lado do Servidor em Nuxt

Busca de Dados no Lado do Servidor em Nuxt

Se você está construindo uma aplicação Nuxt e se perguntando por que seus dados são buscados duas vezes—ou por que componentes compartilhando a mesma chave se comportam de forma inesperada—você não está sozinho. A busca de dados SSR do Nuxt tem regras específicas que confundem até desenvolvedores experientes.

Este artigo explica como useAsyncData e useFetch funcionam no Nuxt 4, cobrindo hidratação de payload, comportamento de navegação, gerenciamento de chaves e as armadilhas que causam mais confusão.

Principais Conclusões

  • O Nuxt executa useFetch e useAsyncData no servidor, serializa as respostas no payload HTML e hidrata no cliente sem rebuscar
  • Componentes compartilhando a mesma chave compartilham estado reativo idêntico—use chaves distintas para instâncias de dados independentes
  • Nas versões atuais do Nuxt 4, certas opções (handler, transform, pick, getCachedData, default, deep) devem corresponder entre chamadas que compartilham uma chave
  • Use useFetch ou useAsyncData para busca segura em SSR; reserve $fetch para manipuladores de eventos e código apenas do cliente

Como o Nuxt Executa a Busca de Dados no Lado do Servidor

Quando você chama useFetch ou useAsyncData em uma página ou componente, o Nuxt executa essa busca no servidor durante a requisição inicial. O servidor serializa a resposta em um payload incorporado no HTML. Quando o cliente hidrata, ele lê este payload em vez de rebuscar—eliminando requisições de rede duplicadas.

const { data } = await useFetch('/api/products')

Esta única linha executa no servidor, incorpora o resultado na página e hidrata perfeitamente no cliente. Sem busca dupla. Sem incompatibilidade de hidratação.

Busca Bloqueante vs. Lazy

Por padrão, o Nuxt bloqueia a navegação até que a busca de dados aguardada seja concluída. Isso garante que sua página renderize com os dados já disponíveis.

Para navegação no lado do cliente, você pode optar pela busca lazy:

const { data, status } = useLazyFetch('/api/comments')

Com busca lazy, a navegação não bloqueia por padrão enquanto a busca é executada em segundo plano. Você precisará lidar com o estado de carregamento no seu template usando a ref status.

Entendendo as Chaves de Busca de Dados do Nuxt

As chaves são centrais para como o Nuxt armazena em cache e deduplica requisições. Toda chamada useFetch usa a URL como sua chave padrão. Para useAsyncData, você fornece a chave explicitamente ou deixa o Nuxt gerar uma determinística para você.

Aqui está a parte crítica: componentes compartilhando a mesma chave compartilham o mesmo estado. Isso inclui as refs data, error, status e pending.

// Componente A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))

// Componente B - compartilha estado com o Componente A
const { data } = await useAsyncData('users', () => $fetch('/api/users'))

Ambos os componentes recebem refs reativas idênticas. Altere uma, e a outra reflete isso.

Regras de Consistência de Chaves

Nas versões atuais do Nuxt 4, o Nuxt impõe consistência para certas opções quando múltiplas chamadas compartilham uma chave. Estas devem corresponder:

  • Função handler
  • Função transform
  • Array pick
  • Função getCachedData
  • Valor default
  • Opção deep

Estas podem diferir com segurança:

  • server
  • lazy
  • immediate
  • dedupe
  • watch

Violar a consistência dispara avisos de desenvolvimento e comportamento imprevisível.

Estratégias Seguras de Chaves

Para dados específicos de rota, inclua parâmetros de rota na sua chave:

const route = useRoute()
const { data } = await useAsyncData(
  `product-${route.params.id}`,
  () => $fetch(`/api/products/${route.params.id}`)
)

Para instâncias independentes que não devem compartilhar estado, use chaves distintas:

const { data: sidebar } = await useAsyncData('users-sidebar', fetchUsers)
const { data: main } = await useAsyncData('users-main', fetchUsers)

Cache de Dados e Comportamento de Dedupe do Nuxt

O Nuxt automaticamente deduplica requisições simultâneas com chaves correspondentes. Se três componentes solicitam a mesma chave simultaneamente, apenas uma requisição de rede é disparada.

A opção dedupe controla o comportamento de atualização:

const { data, refresh } = await useFetch('/api/data', {
  dedupe: 'cancel' // cancela requisições pendentes antes de iniciar uma nova
})

No Nuxt 4.2 e posteriores, o suporte a cancelamento é significativamente melhorado. Quando suportado, respostas obsoletas de rotas anteriores podem ser canceladas ou ignoradas durante navegação rápida, reduzindo o risco de dados desatualizados aparecerem brevemente.

Mais detalhes: https://nuxt.com/docs/api/composables/use-fetch

Armadilhas Comuns

Confundir o useFetch do Nuxt com Outras Bibliotecas

O useFetch do Nuxt não é o mesmo que o useFetch do @vueuse/core ou utilitários similares. A versão do Nuxt lida com a hidratação de payload SSR automaticamente. Usar o useFetch de uma biblioteca diferente ignora isso completamente, causando busca dupla e incompatibilidades de hidratação.

Usar $fetch no Setup Sem useAsyncData

Chamar $fetch diretamente em <script setup> executa tanto no servidor quanto no cliente:

// ❌ Busca duas vezes
const data = await $fetch('/api/users')

// ✅ Busca uma vez, hidrata corretamente
const { data } = await useFetch('/api/users')

Reserve $fetch para manipuladores de eventos e interações apenas do cliente.

Reutilizar Chaves com Opções Conflitantes

Isso dispara avisos e bugs:

// ❌ Opções deep conflitantes
await useAsyncData('users', fetchUsers, { deep: false })
await useAsyncData('users', fetchUsers, { deep: true })

Esperar Dados Antes da Hidratação com server: false

Quando você define server: false, os dados permanecem null até que a hidratação seja concluída—mesmo se você usar await no composable.

Conclusão

O modelo de busca de dados do Nuxt 4 é centrado em execução no servidor, hidratação de payload e cache baseado em chaves. Mantenha as chaves estáveis e únicas por fonte de dados. Garanta consistência de opções ao compartilhar chaves entre componentes. Use useFetch ou useAsyncData para busca segura em SSR, e reserve $fetch para interações no lado do cliente.

Domine esses padrões, e você evitará os bugs de busca dupla e compartilhamento de estado que frustram a maioria dos desenvolvedores Nuxt.

Perguntas Frequentes

Isso normalmente acontece quando você usa $fetch diretamente no script setup em vez de useFetch ou useAsyncData. Chamadas diretas de $fetch são executadas tanto no servidor quanto no cliente. Envolva suas buscas em useFetch ou useAsyncData para aproveitar a hidratação de payload, que busca uma vez no servidor e reutiliza esses dados no cliente.

Use useFetch quando buscar de uma URL diretamente—ele lida com chaves automaticamente com base na URL. Use useAsyncData quando precisar de lógica customizada, múltiplas chamadas de API combinadas, ou controle explícito sobre a chave de cache. Ambos fornecem os mesmos benefícios de hidratação SSR.

Componentes compartilhando a mesma chave compartilham estado reativo idêntico. Para manter os dados independentes, use chaves únicas para cada componente. Por exemplo, use users-sidebar e users-main em vez de apenas users quando dois componentes buscam o mesmo endpoint mas precisam de estado separado.

A opção dedupe controla como o Nuxt lida com múltiplas chamadas de refresh. Definir dedupe como cancel aborta qualquer requisição pendente antes de iniciar uma nova. Isso ajuda a evitar condições de corrida durante interações rápidas do usuário e garante que respostas mais recentes tenham precedência quando o cancelamento é suportado.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay