Fundamentos de React

TP3 completo com fundamentos, questões 1-16, implementação orientada a evidência e roteiro de defesa técnica.

Por Fábio Linhares • Instituto Infnet

BASE
Introdução e Escopo do TP3
Alinhar o enunciado ao resultado esperado: entender, implementar, validar e explicar.
Este material foi elaborado para servir como guia de aprendizagem, e não como coleção de respostas prontas. O foco é conduzir o aluno do entendimento do enunciado até a construção da solução, para que cada resposta seja reproduzida, validada e explicada com clareza.
As questões do TP3 exigem competências centrais de React: criação de componentes, uso de props, organização visual da interface, listas, estado, interação com usuário e consumo de APIs. O objetivo não é decorar comandos, e sim aprender a relação entre dados, estado e renderização.
Ao longo das seções, cada exercício segue um padrão didático: o que a questão pede, quais conceitos são cobrados, como pensar, qual estrutura usar, como validar e como explicar oralmente. Isso reduz erro de entrega incompleta e melhora a defesa técnica.
  • Q1-Q3: componentes de mensagem com props e default.
  • Q4-Q5: telas de login e criação de conta.
  • Q6-Q8: cartões/listas de contato e endereço.
  • Q9-Q12: fluxo com API, useState, useEffect e listas.
  • Q13-Q16: categorias/refeições e surpresa com APIs externas.
EX.01
Fundamentos Que Sustentam Todas as Questões
Consolidar o mínimo técnico para resolver o TP3 sem tentativa e erro.
  • Componentes React e reutilização.
  • Props para dados de entrada e parametrização.
  • useState para dado mutável local.
  • useEffect para carregamento inicial e dependente.
  • map para listas com key estável.
  • Renderização condicional para carregamento, erro e vazio.
  • Inputs e selects controlados.
  • fetch + response.json().
  • Dado derivado versus estado redundante.
  • CSS suficiente para legibilidade e organização visual.
Regra de ouro: antes de criar um novo estado, pergunte se o valor pode ser derivado de estados já existentes. Isso evita complexidade desnecessária.
// Exemplo de dado derivado
const usuarioSelecionado =
  usuarios.find((u) => String(u.id) === usuarioId) || null;
EX.02
Estrutura de Projeto e Componentes-Base
Padronizar arquitetura para evitar retrabalho na implementação das 16 questões.
src/
  componentes/
    msg/Erro.jsx, Atencao.jsx, Sucesso.jsx
    contatos/Contato.jsx, Endereco.jsx
    posts/ListaPosts.jsx
    refeicoes/ListaCategorias.jsx
  paginas/
    Ex01 ... Ex16
  App.jsx
  main.jsx
Antes de começar a codar, o aluno precisa entender a lógica da organização do projeto. O TP3 pede um único projeto React, mas esse projeto não deve virar um arquivo gigante e confuso. A ideia correta é separar o que é página de teste do que é componente reutilizável. As páginas ficam em src/paginas porque cada uma representa um exercício sendo testado. Os componentes ficam em src/componentes porque são peças reaproveitáveis da interface, como mensagens, cartões, listas e formulários.
O App.jsx funciona como ponto de teste. Nele, você importa uma página por vez e renderiza apenas aquela que está estudando naquele momento. Isso ajuda a validar exercício por exercício, evita confusão visual e respeita o enunciado, que pede um único projeto com as páginas sendo chamadas no App.jsx. Em termos práticos, a página resolve o exercício; os componentes sustentam a página.
Regra prática de organização: se um trecho da interface pode ser reutilizado, ele deve virar componente. Se um arquivo existe apenas para testar um exercício inteiro, ele pode ficar em src/paginas. Essa separação melhora leitura, manutenção e defesa técnica.
Erro comum: colocar tudo dentro de App.jsx. Isso até pode funcionar em casos muito pequenos, mas enfraquece a estrutura, dificulta a reutilização e faz o aluno perder a noção de componente como unidade de interface.
Checklist de estrutura correta: existe um único projeto React; o App.jsx renderiza uma página por vez; os componentes reutilizáveis estão separados por tema; cada página importa apenas o que precisa; e a navegação entre exercícios acontece comentando e descomentando a chamada correspondente.
Q1-Q3 reaproveitam o mesmo padrão de componente de mensagem com mudança de estilo e default. Q6-Q8 reaproveitam o padrão de cartão para contato/endereço. Q11-Q12 reaproveitam lista de posts com fontes diferentes de dados.
Organização por componente reduz acoplamento, facilita teste por questão e melhora explicação técnica na apresentação.
EX.03
Q1-Q3: Mensagens de Erro, Atenção e Sucesso
Aplicar props, default value e estilização para componentes de feedback.
O que a questão pede: componente visual com titulo e mensagem por props, com fallback para o título.
export default function Erro({ titulo = "ERRO", mensagem }) {
  return (
    <div className="msg-card erro">
      <h3>{titulo}</h3>
      <p>{mensagem}</p>
    </div>
  );
}
  • Q2 e Q3 seguem o mesmo padrão mudando default e classe CSS.
  • Conceito central: componente parametrizado por props.
  • Validação: sem enviar titulo, o default deve aparecer corretamente.
EX.04
Q4-Q5: Telas de Login e Criação de Conta
Construir interface de formulário estilizada, sem exigir autenticação real.
As questões pedem interface organizada (labels, inputs e botão), não backend de autenticação.
export default function Login() {
  return (
    <div className="auth-box">
      <h2>Login</h2>
      <form className="auth-form">
        <label>Email</label>
        <input type="email" />
        <label>Senha</label>
        <input type="password" />
        <button type="submit">Entrar</button>
      </form>
    </div>
  );
}
Q5 reaproveita a mesma base adicionando nome e confirmação de senha.
Erro comum: entregar apenas inputs sem hierarquia visual e sem classes CSS coerentes.
EX.05
Q6-Q8: Cartões e Listas de Contato/Endereço
Trabalhar props com objeto, lista com map e dados simulados com Faker.
const contatosFixos = Array.from({ length: 5 }, () => ({
  id: faker.string.uuid(),
  nome: faker.person.fullName(),
  email: faker.internet.email(),
  telefone: faker.phone.number(),
}));

{contatosFixos.map((contato) => (
  <Contato key={contato.id} contato={contato} />
))}
  • Q6: cartão de contato a partir de objeto por props.
  • Q7: lista de cartões com dados fixos gerados pelo Faker.
  • Q8: cartão de endereço com CEP, logradouro, complemento, bairro, localidade e UF.
Boa prática: gerar lista fixa fora do componente para evitar recriação de dados a cada render.
EX.06
Q9: Consulta de CEP (ViaCEP)
Combinar input controlado, validação, chamada de API e renderização condicional.
const [cep, setCep] = useState("");
const [endereco, setEndereco] = useState(null);
const [erro, setErro] = useState("");

const cepLimpo = cep.replace(/\D/g, "");
if (cepLimpo.length !== 8) {
  setErro("CEP inválido.");
  return;
}
Esta questão é o primeiro ponto do TP em que o aluno realmente precisa articular estado, evento, API e renderização condicional ao mesmo tempo. O raciocínio completo é este: o usuário digita um CEP; esse valor fica guardado em estado; ao clicar no botão, o React executa uma função assíncrona; essa função limpa o texto digitado, valida se existem 8 dígitos, consulta a API do ViaCEP e, se tudo der certo, salva o endereço retornado em estado. Quando o estado muda, a interface é renderizada novamente, e o componente de endereço passa a aparecer na tela.
Repare que aqui existem três estados com papéis diferentes. cep guarda a entrada do usuário. endereco guarda o resultado válido da API. erro guarda a mensagem de falha, caso algo dê errado. Essa separação é importante porque cada estado responde a uma pergunta diferente: o que o usuário digitou? qual foi o resultado da consulta? houve algum problema?
Estrutura mental correta: input controlado -> clique no botão -> sanitização do CEP -> validação -> fetch -> response.json() -> atualização do estado -> renderização do componente Endereco.
Erros comuns: tentar consultar sem limpar traços e pontos; esquecer que a API pode retornar erro: true; tentar renderizar o cartão de endereço antes de existir um objeto válido; e tratar o input como não controlado, perdendo o valor digitado no fluxo da interface.
Como validar corretamente: digite um CEP válido e confirme se o cartão aparece com CEP, logradouro, complemento, bairro, localidade e UF. Depois teste um CEP inválido e confirme se a página exibe uma mensagem de erro em vez de tentar renderizar dados inexistentes.
  • Sem CEP válido, não chama API.
  • Se API retornar erro, exibe mensagem clara ao usuário.
  • Se retornar endereço, renderiza cartão de endereço.
Erro comum: não limpar caracteres não numéricos e gerar consulta inválida.
EX.07
Q10-Q12: Usuários e Posts com Efeito Dependente
Controlar seleção de usuário e carregar dados dinamicamente sem estado redundante.
useEffect(() => {
  async function carregarUsuarios() {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    setUsuarios(await response.json());
  }
  carregarUsuarios();
}, []);

useEffect(() => {
  async function carregarPosts() {
    if (!usuarioId) {
      setPosts([]);
      return;
    }
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts?userId=${usuarioId}`
    );
    setPosts(await response.json());
  }
  carregarPosts();
}, [usuarioId]);
Este bloco reúne três exercícios que parecem parecidos, mas não são iguais. A Q10 pede carregar usuários, permitir a seleção em um dropdown e mostrar os dados do usuário escolhido. A Q11 pede exibir a lista completa de posts. Já a Q12 combina as duas ideias: primeiro o usuário escolhe uma pessoa, depois a aplicação busca apenas os posts relacionados a essa pessoa. O ponto central aqui é entender que existe um dado base e um dado dependente.
Na Q10, o dado base é a lista de usuários. Ela deve ser carregada uma vez, na montagem do componente, com useEffect(..., []). O valor escolhido no dropdown fica em estado, normalmente como usuarioId. A partir desse estado e da lista já carregada, é possível derivar o usuário selecionado com find. Isso é importante: o usuário selecionado não precisa, necessariamente, de um novo estado. Em muitos casos, ele pode ser calculado a partir do que já existe.
Na Q11, a lógica é mais simples: a página só precisa buscar os posts e renderizar a lista. Já na Q12 aparece o efeito dependente. O segundo useEffect só deve rodar quando usuarioId mudar. É exatamente por isso que a dependência é [usuarioId]. Sem usuário selecionado, a lista de posts deve ficar vazia. Com usuário selecionado, a aplicação consulta a API usando ?userId=... e atualiza o estado de posts.
Regra didática importante: primeiro carrega a lista base; depois reage à escolha do usuário; só então carrega os dados filtrados. Esse fluxo é mais limpo do que tentar buscar tudo ao mesmo tempo sem critério.
Erros comuns: guardar em estado um dado que poderia ser derivado com find; tentar carregar posts antes de existir usuarioId; esquecer de limpar os posts quando o usuário volta para a opção vazia; e não perceber que Q10, Q11 e Q12 exigem três comportamentos diferentes, mesmo compartilhando parte da lógica.
Como validar: na Q10, selecione usuários diferentes e confirme se os dados exibidos mudam. Na Q11, a lista de posts deve aparecer completa. Na Q12, a seleção do usuário deve alterar a lista de posts exibida, mostrando apenas os posts daquele usuário.
  • Q10: dropdown de usuários e exibição do selecionado.
  • Q11: lista completa de posts.
  • Q12: posts filtrados por usuário selecionado.
Como pensar: primeiro carrega a lista base (usuários), depois aplica efeito dependente para dados filtrados (posts).
EX.08
Q13-Q15: Categorias, Refeições e Receita Aleatória
Trabalhar TheMealDB com dropdown dependente e ação aleatória orientada por evento.
// Q14: carregar refeições por categoria
const response = await fetch(
  `https://www.themealdb.com/api/json/v1/1/filter.php?c=${encodeURIComponent(categoriaSelecionada)}`
);

// Q15: surpresa de receita
const randomResponse = await fetch(
  "https://www.themealdb.com/api/json/v1/1/random.php"
);
Aqui o aluno precisa entender que o TheMealDB não devolve sempre o mesmo formato de resposta. Na consulta de categorias, a lista real vem em data.categories. Na consulta de refeições por categoria, a lista real vem em data.meals. Já na receita aleatória, o retorno também vem em data.meals, mas com um único item dentro do array. Ou seja: a API é a mesma família, mas o payload muda conforme o endpoint.
A Q13 é a mais simples desse grupo: buscar categorias e renderizar nome e descrição. A Q14 exige duas etapas ligadas entre si: carregar categorias para o dropdown e, depois, quando o usuário escolhe uma delas, buscar as refeições correspondentes. Já a Q15 não depende de seleção; depende apenas de um botão que dispara uma ação assíncrona e exibe o resultado aleatório.
O raciocínio da Q14 é especialmente importante. O dropdown é controlado por estado. Quando categoriaSelecionada muda, um useEffect dependente dessa categoria precisa rodar. Esse efeito consulta o endpoint filter.php?c=... e atualiza a lista de refeições. Se nenhuma categoria estiver selecionada, a lista deve ser esvaziada para evitar resultado antigo na tela.
Fluxo correto da Q14: carregar categorias -> selecionar categoria -> atualizar estado -> disparar efeito dependente -> buscar refeições -> renderizar nova lista.
Erros comuns: fixar uma categoria no código e ignorar a seleção do usuário; esquecer que a resposta pode vir sem refeições; tratar a receita aleatória como lista comum; e não distinguir os três formatos de payload usados neste bloco.
Como validar: na Q13, a lista de categorias deve mostrar nome e descrição. Na Q14, trocar a categoria no dropdown deve alterar a lista de refeições exibida. Na Q15, clicar em Me Surpreenda deve mostrar uma nova receita, com dados coerentes do mesmo prato.
  • Q13: listar categorias com nome e descrição.
  • Q14: ao trocar categoria, atualizar lista de refeições.
  • Q15: botão Me Surpreenda para receita aleatória.
Erro comum: fixar categoria no código e ignorar a seleção do usuário.
EX.09
Q16: País Aleatório com Rest Countries
Buscar país aleatório exibindo pelo menos 5 campos com payload enxuto.
const response = await fetch(
  "https://restcountries.com/v3.1/all?fields=name,capital,region,population,flags,cca3"
);
const data = await response.json();
const indice = Math.floor(Math.random() * data.length);
setPais(data[indice]);
Esta questão parece simples, mas ensina uma habilidade importante: buscar uma coleção grande, escolher um item aleatório e exibir apenas os campos úteis para a interface. O fluxo é: consultar a API de países, converter a resposta para JSON, obter um índice aleatório, selecionar um país do array e guardar esse objeto em estado. Depois disso, a renderização condicional exibe os dados escolhidos.
O ideal aqui é escolher campos que mostrem variedade de tipos de dado. Um conjunto bom é: nome comum, nome oficial, capital, região, população e bandeira. Isso permite trabalhar texto simples, texto aninhado, array opcional e imagem. Esse exercício também é ótimo para mostrar que nem todo campo vem em formato plano. Por exemplo, a capital costuma vir como array, e por isso o acesso mais seguro é capital?.[0].
Boa prática: usar o parâmetro fields= no endpoint para pedir apenas os campos que a interface vai usar. Isso reduz payload, deixa o exemplo mais claro e ajuda o aluno a entender melhor o formato esperado dos dados.
Erros comuns: esquecer que a capital pode não existir; tentar usar o objeto inteiro sem escolher os campos relevantes; não usar renderização condicional; e tratar um array de países como se a resposta fosse um único objeto.
Como validar: a cada clique em Me Surpreenda, a tela deve mostrar um país plausível com pelo menos cinco dados visíveis e uma bandeira correspondente. O conteúdo pode repetir eventualmente, mas o mecanismo deve estar correto.
  • Campos recomendados: nome, nome oficial, capital, região, população e bandeira.
  • Uso de fields= reduz payload e simplifica o consumo.
  • Renderização condicional evita acesso a campo inexistente antes da resposta.
EX.10
Roteiro de Defesa Técnica e Erros Frequentes
Garantir que o aluno consiga explicar e justificar qualquer questão do TP3.
Roteiro de explicação: o que a questão pede, qual componente foi criado, quais dados entram, se os dados vêm de props/estado/API, qual evento altera estado e como foi validado.
Exemplo (Q12): select controlado guarda usuarioId; useEffect dependente busca posts por userId; resultado vai para estado e a lista renderiza só os posts do usuário selecionado.
  • Confundir props com estado.
  • Fazer tudo em App.jsx sem componentização.
  • Esquecer key em listas.
  • Não tratar caso vazio/erro de API.
  • Criar estado demais quando o valor é derivável.
  • Entregar interface sem estilização mínima exigida.
EX.11
Checklist de Correção Antes da Entrega
Fechar o TP3 com rastreabilidade de requisito por questão.
  • Q1-Q3 com título default funcionando por props.
  • Q4-Q5 com formulário organizado e estilizado.
  • Q6-Q8 com cartões de contato/endereço completos.
  • Q7 com Faker + map + key.
  • Q9 com consulta de CEP e tratamento de erro.
  • Q10 com dropdown de usuários e exibição dinâmica.
  • Q11 com lista de posts da API.
  • Q12 com posts filtrados por usuário selecionado.
  • Q13-Q14 com categorias e refeições por seleção.
  • Q15 com receita aleatória.
  • Q16 com país aleatório e mínimo de 5 dados.
Se todos os itens acima estiverem comprovados, o aluno está apto a entregar e explicar o TP3 com segurança.
CHECK
Validação Final de Conformidade
Consolidar aderência editorial, técnica e semântica antes de publicar.
Antes de considerar o TP fechado, o aluno precisa verificar não só se "apareceu alguma coisa na tela", mas se cada tipo de competência realmente foi demonstrado. O objetivo deste check não é apenas confirmar entrega visual. É confirmar domínio técnico mínimo.
  • Props: os componentes recebem dados de fora quando o enunciado pede parametrização?
  • Estado: inputs, seleções, resultados de API e mensagens de erro estão em useState quando precisam mudar?
  • Dado derivado: algum valor foi calculado a partir de outro, em vez de virar estado redundante?
  • Listas: toda lista dinâmica foi renderizada com map e key estável?
  • Efeitos: carregamentos iniciais usam useEffect com dependências corretas?
  • API: o código usa fetch, response.json() e leitura correta do payload?
  • Renderização condicional: erro, vazio, seleção e resultado aparecem apenas quando fazem sentido?
  • Estilo: os componentes estão visualmente organizados, legíveis e compatíveis com a ideia de "estilizado"?
Se o aluno consegue responder "sim" para esse bloco inteiro e ainda explicar o caminho de dados de cada página, então ele não apenas montou a solução: ele entendeu a solução.
  • Estrutura no padrão do acervo: BASE + EX.01..EX.11 + CHECK.
  • Título final aplicado: Fundamentos de React.
  • Conteúdo cobrindo fundamentos, Q1..Q16, erros e checklist.
  • Identidade visual, navegação e scripts compartilhados preservados.
Página pronta para publicação final com foco em ensino completo, validação e defesa técnica.