<aside> <img src="/icons/arrow-northeast_gray.svg" alt="/icons/arrow-northeast_gray.svg" width="40px" />
Índice
</aside>
<aside> <img src="/icons/notion_green.svg" alt="/icons/notion_green.svg" width="40px" />
Conteúdos
Anatomia de um componente .vue
Interpolação e reatividade com ref e computed
Diretivas: v-bind, v-on, v-if, v-for e v-model
Criando o projeto Gumball Verse
Primeira requisição com useFetch
Layout, base do projeto e nuxt.config.ts
Consumindo a API nas listagens
Páginas de detalhes com rotas dinâmicas
Tratando o erro 404 com createError
Títulos das páginas com useHead
Filtros, paginação e busca com debounce
Desafio: título e favicon dinâmicos
</aside>
Bem-vindo à Parte 3, a integração com a API! Vamos começar pelas seções de destaque da página inicial: a listagem de personagens e a listagem de lugares. Ambas já existem na interface base, mas ainda não buscam nenhum dado. Vamos resolver isso, entendendo bem o que cada trecho significa.
Abra o componente app/components/CharactersListing/index.vue e deixe-o assim:
<script setup>
const { data, error } = await useFetch('https://gumball-api-server.vercel.app/characters', {
query: { limit: 8 },
});
</script>
<template>
<section class="section">
<div class="container">
<SectionHeader
eyebrow="Seção 01 · Elenco"
lead="Da família Watterson aos colegas da Elmore Junior High, cada um mais imprevisível que o outro."
see-all-url="/characters"
>
Os moradores mais <em>esquisitos</em> de Elmore
</SectionHeader>
<StateMessage v-if="error">
Não foi possível carregar os personagens. Tente novamente mais tarde.
</StateMessage>
<div v-else class="grid grid--characters">
<CharacterCard
v-for="currentCharacter in data?.data"
:key="currentCharacter.id"
:id="currentCharacter.id"
:name="currentCharacter.name"
:image="currentCharacter.image"
:species="currentCharacter.species"
:occupation="currentCharacter.occupation"
:role="currentCharacter.role"
:color="getCharacterColor(currentCharacter.colors)"
/>
</div>
</div>
</section>
</template>
data, ele também devolve o error, que fica preenchido quando a requisição falha;await garante que os dados cheguem antes de a página ser montada no servidor. Assim, o HTML já vai para o navegador com os personagens, o que é ótimo para o SEO;query vira parâmetros na URL. Aqui, { limit: 8 } vira ?limit=8, e a API devolve só 8 personagens;data, com a lista de itens, e meta, com as informações de paginação. Por isso acessamos data?.data. O ?. (optional chaining) evita erros enquanto ainda não há dados.<aside>
🔎 Dica: para entender o formato da resposta, adicione console.log(data.value) logo depois do useFetch e veja o resultado no terminal. Lembre-se: no script usamos .value, no template não.
</aside>
data?.data, um <CharacterCard> é criado;id do personagem, que é único, para o Vue identificar cada card;:, porque os valores vêm de variáveis JavaScript, e não de textos fixos. Lembre da regra de ouro da Parte 1!composables/ que escolhe a cor do card a partir das cores do personagem. Por ser um composable, ela também é importada automaticamente.Com o v-if="error", se a API falhar, mostramos uma mensagem amigável com o componente StateMessage em vez de quebrar a página. O v-else garante que a grade de personagens só aparece quando não há erro.