JavaScript, JSX, listas, state e props (16 exercícios).
Ao encarar estes 16 exercícios, você vai atravessar o “miolo duro” do React: o ponto em que a interface deixa de ser um amontoado de tags e vira um sistema previsível, construído a partir de dados, regras e componentes.
Os desafios começam no básico que muita gente ignora: entender o que o JavaScript realmente está fazendo quando você declara variáveis (let/const), manipula valores primitivos (strings, números, booleanos) e lida com tipos referenciados (objetos e arrays). Aqui você vai treinar uma habilidade que separa o iniciante do competente: ler dados, transformar dados e apresentar dados sem se perder em “gambiarras” de DOM.
Em seguida, você vai encarar a parte que dá identidade ao React: pensar em UI como função do estado. Você vai montar páginas simples com JSX, mas também vai aprender a construir interfaces que mudam conforme condições (hora do dia, status do usuário) e que surgem de coleções (listas de tarefas, cards de produtos). Isso exige um salto mental: em vez de “mandar” a tela mudar, você descreve como ela deve ser para cada situação — e deixa o React fazer o trabalho mecânico.
Você também vai enfrentar uma das áreas onde bugs mais aparecem em aplicações reais: renderizar listas corretamente. Parece trivial até você perceber que “loop + key” é o tipo de detalhe que, se feito errado, cria problemas estranhos que parecem assombração (inputs trocando de lugar, itens reaparecendo, estado indo parar no componente errado). Resolver bem esses exercícios te dá uma competência prática de engenharia: evitar bugs que não são óbvios.
Outro desafio importante é aprender a transformar lógica em funções limpas (soma, conversão de temperatura, par/ímpar, diferença). Isso não é “só matemática”: é treinar pensamento funcional aplicado, onde você consegue isolar regras, testar mentalmente e reaproveitar código sem efeitos colaterais desnecessários. Quando isso se encaixa com React, seu código fica mais previsível e mais fácil de manter.
A reta final costura as peças mais valiosas para construir aplicações de verdade: componentes reutilizáveis, props como contrato (dados descem, ações sobem) e state para lidar com interação (contador). Se você concluir todos, você terá passado pelo essencial de “pensar em componentes” e de projetar a interface a partir de dados e responsabilidades, não a partir de improviso.
Se você conseguir resolver todas as questões com entendimento (não só copiando), você dominará, na prática:
• Fluência de JavaScript aplicada ao React: declarar, compor e usar variáveis, funções e expressões para gerar UI de forma limpa.
• Modelagem de dados simples e complexos (primitivos, objetos, arrays) e renderização segura.
• Condicionais e coleções com map e chaves estáveis, evitando bugs típicos.
• Modelo mental do React: “a tela é consequência do estado”, para prever comportamento antes de rodar.
• Componentes reutilizáveis e passagem de dados via props, organizando a UI em responsabilidades claras.
• Interações básicas com state, sem confundir “mudar variável” com “mudar a UI”.
• Depuração com calma: dados → render → tela, em vez de tratar React como magia.
Por fim, você não terá só um conjunto de respostas. Você terá uma base operacional para começar a construir interfaces React pequenas e médias com previsibilidade e, mais importante, com método.
App.jsx. Você estuda “um por vez” comentando/descomentando o que renderiza.
src/App.jsx e src/App.css pelos códigos desta página.npm create vite@latest fundamentos-react -- --template react
cd fundamentos-react
npm install
npm run dev
flex-direction define o eixo principal. justify-content alinha no eixo principal; align-items no eixo transversal.justify-content vs align-items.justify-content sempre é “horizontal”. O eixo depende de flex-direction.map e um <time> por item.key estável e se a UI está vindo de dados.http://localhost:5173, você deve ver a saída do componente do exercício 3 quando ele for o único renderizado.const por padrão; use let apenas quando realmente vai reatribuir.let: é com useState (ex. 15).map.// exemplos de referência dentro do App.jsx
// Ex4: let/const, Ex5: primitivos, Ex6: objeto + array + map + key
`texto ${variavel}`.map e key estável.index como key quando a lista pode mudar de ordem/itens, porque pode “embaralhar” UI e estado interno.// dica de verificação
// - liste com map
// - use key estável (string ou id)
// - force mudanças na lista e veja se a UI permanece coerente
<Card />) + map em array de objetos.useState e atualização baseada no valor anterior: setCount(c => c + 1).import "./App.css";
import { useState } from "react";
function saudacaoPorHora(h) {
if (h >= 5 && h < 12) return "Bom dia";
if (h >= 12 && h < 18) return "Boa tarde";
return "Boa noite";
}
function Ex1_FlexboxEixos() {
return (
<div className="stack">
<h3>O que é React</h3>
<p>
React é uma biblioteca para construir interfaces a partir de componentes.
Você descreve a UI como uma função do estado e o React recalcula a tela
quando o estado muda.
</p>
<div className="grid2">
<div className="panel">
<h4>Flex: row (eixo principal horizontal)</h4>
<div className="flexDemo row">
<div className="box">A</div>
<div className="box">B</div>
<div className="axisHint">
<div><b>main axis</b> →</div>
<div><b>cross axis</b> ↓</div>
</div>
</div>
<p className="note">
Aqui, <code>justify-content</code> mexe no horizontal (main) e{" "}
<code>align-items</code> no vertical (cross).
</p>
</div>
<div className="panel">
<h4>Flex: column (eixo principal vertical)</h4>
<div className="flexDemo column">
<div className="box">A</div>
<div className="box">B</div>
<div className="axisHint">
<div><b>main axis</b> ↓</div>
<div><b>cross axis</b> →</div>
</div>
</div>
<p className="note">
Aqui, o eixo principal virou vertical. Agora{" "}
<code>justify-content</code> mexe no vertical (main).
</p>
</div>
</div>
</div>
);
}
function Ex2_HistoricoReact() {
const eventos = [
{ ano: "2011", texto: "Uso interno (News Feed) e evolução inicial" },
{ ano: "2012", texto: "Adoção em aplicações do ecossistema Instagram" },
{ ano: "2013", texto: "Open-source (JSConf US)" },
{ ano: "2015", texto: "React Native: anúncio e abertura do projeto" },
{
ano: "2017",
texto: "React 16: grande atualização (base para evoluções internas)",
},
{ ano: "2019", texto: "Hooks estáveis no React 16.8" },
{ ano: "2024", texto: "React 19: novas capacidades e melhorias" },
];
return (
<div className="stack">
<h3>Histórico do ReactJs</h3>
<ol className="timeline">
{eventos.map((e) => (
<li key={e.ano} className="timelineItem">
<time className="timelineYear">{e.ano}</time>
<span>{e.texto}</span>
</li>
))}
</ol>
<p className="note">
A lista foi renderizada com <code>map</code>, e cada item tem{" "}
<code>key</code> estável.
</p>
</div>
);
}
function Ex3_HelloReact() {
return (
<div className="stack">
<h3>Hello, React!</h3>
<p className="note">
Se você renderizar somente este componente no App, você tem exatamente a
“tela inicial” do exercício 3.
</p>
</div>
);
}
function Ex4_LetConst() {
let nome = "Ana";
const idade = 23;
nome = nome.toUpperCase();
return (
<div className="stack">
<h3>let e const</h3>
<p>
Nome: <b>{nome}</b>
</p>
<p>
Idade: <b>{idade}</b>
</p>
<p className="note">
Em React, para “mudar valores na tela”, normalmente você usa{" "}
<code>useState</code> (exercício 15), não reatribuição com{" "}
<code>let</code>.
</p>
</div>
);
}
function Ex5_Primitivos() {
const nome = "João";
const idade = 30;
const assinante = true;
return (
<div className="stack">
<h3>Perfil com valores primitivos</h3>
<p>
Nome: <b>{nome}</b>
</p>
<p>
Idade: <b>{idade}</b>
</p>
<p>
Status:{" "}
{assinante ? (
<span className="tag ok">Assinante</span>
) : (
<span className="tag">Gratuito</span>
)}
</p>
</div>
);
}
function Ex6_ObjetoArray() {
const livro = { titulo: "Estruturas de Dados", autor: "A. Pessoa", ano: 2022 };
const capitulos = ["Listas", "Pilhas", "Filas", "Árvores", "Grafos"];
return (
<div className="stack">
<h3>Objeto (livro) + Array (capítulos)</h3>
<p>
<b>{livro.titulo}</b> — {livro.autor} ({livro.ano})
</p>
<ul>
{capitulos.map((c) => (
<li key={c}>{c}</li>
))}
</ul>
<p className="note">
Reparou na <code>key</code>? Aqui o capítulo (string) é estável,
então funciona bem.
</p>
</div>
);
}
function Ex7_TemplateStrings() {
const nome = "Marina";
const agora = new Date();
const hora = agora.getHours();
const msg = `Bem-vindo(a), ${nome}! Agora são ${hora}h. ${saudacaoPorHora(hora)}!`;
return (
<div className="stack">
<h3>Template Strings</h3>
<p>{msg}</p>
<p className="note">
Template string usa crase: <code>{'`texto ${variavel}`'}</code>.
</p>
</div>
);
}
function Ex8_CondicionalHora() {
const hora = new Date().getHours();
const saudacao = saudacaoPorHora(hora);
return (
<div className="stack">
<h3>Condicional por hora</h3>
<p>
Agora são <b>{hora}h</b> → <b>{saudacao}</b>
</p>
</div>
);
}
function Ex9_ListaTarefas() {
const tarefas = ["Estudar JSX", "Praticar props", "Treinar map + key", "Revisar useState"];
return (
<div className="stack">
<h3>Loop para renderizar lista</h3>
<ul>
{tarefas.map((t) => (
<li key={t}>{t}</li>
))}
</ul>
<p className="note">
Evite <code>index</code> como <code>key</code> quando a lista pode mudar:
isso causa bugs “fantasmas”.
</p>
</div>
);
}
function Ex10_FuncaoSoma() {
function soma(a, b) {
return a + b;
}
const a = 7;
const b = 5;
return (
<div className="stack">
<h3>Função: soma</h3>
<p>
{a} + {b} = <b>{soma(a, b)}</b>
</p>
</div>
);
}
function Ex11_CelsiusFahrenheit() {
function cParaF(c) {
return (c * 9) / 5 + 32;
}
const c = 25;
return (
<div className="stack">
<h3>Função: Celsius → Fahrenheit</h3>
<p>
{c}°C = <b>{cParaF(c)}°F</b>
</p>
</div>
);
}
function Ex12_ArrowDiferenca() {
const diferenca = (a, b) => a - b;
const a = 10;
const b = 4;
return (
<div className="stack">
<h3>Arrow Function: diferença</h3>
<p>
{a} - {b} = <b>{diferenca(a, b)}</b>
</p>
</div>
);
}
function Ex13_ArrowParImpar() {
const ehPar = (n) => n % 2 === 0;
const n = 7;
return (
<div className="stack">
<h3>Arrow Function: par ou ímpar</h3>
<p>
{n} é <b>{ehPar(n) ? "par" : "ímpar"}</b>
</p>
</div>
);
}
function Card({ titulo, preco, estoque }) {
return (
<div className="card">
<h4 className="cardTitle">{titulo}</h4>
<p className="cardPrice">R$ {preco.toFixed(2)}</p>
<p className="note">
{estoque > 0 ? (
<span className="tag ok">Em estoque</span>
) : (
<span className="tag">Indisponível</span>
)}
</p>
</div>
);
}
function Ex14_CardsDinamicos() {
const produtos = [
{ id: "p1", titulo: "Teclado", preco: 129.9, estoque: 12 },
{ id: "p2", titulo: "Mouse", preco: 79.9, estoque: 0 },
{ id: "p3", titulo: "Monitor", preco: 899.0, estoque: 5 },
];
return (
<div className="stack">
<h3>Cards dinâmicos (map + componente)</h3>
<div className="cardsGrid">
{produtos.map((p) => (
<Card key={p.id} titulo={p.titulo} preco={p.preco} estoque={p.estoque} />
))}
</div>
<p className="note">
Repare: <code>key</code> estável (id), e dados indo por <code>props</code>.
</p>
</div>
);
}
function Ex15_ContadorState() {
const [count, setCount] = useState(0);
return (
<div className="stack">
<h3>State: contador</h3>
<div className="counter">
<button onClick={() => setCount((c) => c - 1)}>-</button>
<span className="counterValue">{count}</span>
<button onClick={() => setCount((c) => c + 1)}>+</button>
</div>
<p className="note">
Use <code>setCount(c => c + 1)</code> quando o próximo valor depende do anterior.
</p>
</div>
);
}
function Filho({ nome, area }) {
return (
<div className="panel">
<p>
Nome recebido via props: <b>{nome}</b>
</p>
<p>
Área recebida via props: <b>{area}</b>
</p>
</div>
);
}
function Ex16_PropsPaiFilho() {
const nome = "Carlos";
const area = "Frontend (React)";
return (
<div className="stack">
<h3>Props: pai → filho</h3>
<p className="note">
O pai define os dados e passa para o filho. O filho não “adivinha” nada: só apresenta.
</p>
<Filho nome={nome} area={area} />
</div>
);
}
function Secao({ id, titulo, children }) {
return (
<section id={id} className="section">
<h2 className="sectionTitle">{titulo}</h2>
{children}
</section>
);
}
export default function App() {
const links = [
{ id: "ex1", label: "Ex1" },
{ id: "ex2", label: "Ex2" },
{ id: "ex3", label: "Ex3" },
{ id: "ex4", label: "Ex4" },
{ id: "ex5", label: "Ex5" },
{ id: "ex6", label: "Ex6" },
{ id: "ex7", label: "Ex7" },
{ id: "ex8", label: "Ex8" },
{ id: "ex9", label: "Ex9" },
{ id: "ex10", label: "Ex10" },
{ id: "ex11", label: "Ex11" },
{ id: "ex12", label: "Ex12" },
{ id: "ex13", label: "Ex13" },
{ id: "ex14", label: "Ex14" },
{ id: "ex15", label: "Ex15" },
{ id: "ex16", label: "Ex16" },
];
return (
<div className="page">
<header className="header">
<h1>Fundamentos de React — 16 exercícios</h1>
<nav className="nav">
{links.map((l) => (
<a key={l.id} href={`#${l.id}`} className="navLink">
{l.label}
</a>
))}
</nav>
</header>
<main className="main">
<Secao id="ex1" titulo="Exercício 1 — Flexbox (direção/eixos) + O que é React">
<Ex1_FlexboxEixos />
</Secao>
<Secao id="ex2" titulo="Exercício 2 — Histórico do ReactJs (linha do tempo)">
<Ex2_HistoricoReact />
</Secao>
<Secao id="ex3" titulo='Exercício 3 — "Hello, React!"'>
<Ex3_HelloReact />
</Secao>
<Secao id="ex4" titulo="Exercício 4 — let e const">
<Ex4_LetConst />
</Secao>
<Secao id="ex5" titulo="Exercício 5 — Valores primitivos">
<Ex5_Primitivos />
</Secao>
<Secao id="ex6" titulo="Exercício 6 — Objeto e array">
<Ex6_ObjetoArray />
</Secao>
<Secao id="ex7" titulo="Exercício 7 — Template Strings">
<Ex7_TemplateStrings />
</Secao>
<Secao id="ex8" titulo="Exercício 8 — Condicionais por hora">
<Ex8_CondicionalHora />
</Secao>
<Secao id="ex9" titulo="Exercício 9 — Loop para lista de tarefas">
<Ex9_ListaTarefas />
</Secao>
<Secao id="ex10" titulo="Exercício 10 — Função soma">
<Ex10_FuncaoSoma />
</Secao>
<Secao id="ex11" titulo="Exercício 11 — Função Celsius → Fahrenheit">
<Ex11_CelsiusFahrenheit />
</Secao>
<Secao id="ex12" titulo="Exercício 12 — Arrow Function diferença">
<Ex12_ArrowDiferenca />
</Secao>
<Secao id="ex13" titulo="Exercício 13 — Arrow Function par/ímpar">
<Ex13_ArrowParImpar />
</Secao>
<Secao id="ex14" titulo="Exercício 14 — Cards dinâmicos">
<Ex14_CardsDinamicos />
</Secao>
<Secao id="ex15" titulo="Exercício 15 — State (contador)">
<Ex15_ContadorState />
</Secao>
<Secao id="ex16" titulo="Exercício 16 — Props (pai → filho)">
<Ex16_PropsPaiFilho />
</Secao>
</main>
</div>
);
}
:root {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
color: #111;
background: #fafafa;
}
* { box-sizing: border-box; }
.page { max-width: 1100px; margin: 0 auto; padding: 24px; }
.header { position: sticky; top: 0; background: #fafafa; padding-bottom: 12px; z-index: 10; }
.header h1 { margin: 0 0 10px 0; font-size: 20px; }
.nav {
display: flex;
gap: 8px;
flex-wrap: wrap;
align-items: center;
}
.navLink {
text-decoration: none;
color: #0b57d0;
background: #e8f0fe;
padding: 6px 10px;
border-radius: 999px;
font-size: 12px;
}
.main { margin-top: 16px; display: grid; gap: 18px; }
.section {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 12px;
padding: 16px;
}
.sectionTitle { margin: 0 0 12px 0; font-size: 16px; }
.stack { display: grid; gap: 10px; }
.note { margin: 0; color: #555; font-size: 13px; }
code { background: #f2f2f2; padding: 2px 6px; border-radius: 6px; }
.grid2 { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 900px) {
.grid2 { grid-template-columns: 1fr 1fr; }
}
.panel {
border: 1px dashed #d8d8d8;
border-radius: 12px;
padding: 12px;
background: #fcfcfc;
}
.flexDemo {
display: flex;
gap: 10px;
padding: 10px;
border-radius: 12px;
border: 1px solid #eee;
background: #fff;
justify-content: flex-start;
align-items: center;
min-height: 110px;
}
.flexDemo.row { flex-direction: row; }
.flexDemo.column { flex-direction: column; }
.box {
width: 52px;
height: 52px;
display: grid;
place-items: center;
border-radius: 10px;
border: 1px solid #ddd;
background: #f6f6f6;
font-weight: 700;
}
.axisHint {
margin-left: auto;
font-size: 12px;
color: #444;
padding: 6px 10px;
border-radius: 10px;
background: #f7f7ff;
border: 1px solid #ececff;
}
.timeline { margin: 0; padding-left: 18px; display: grid; gap: 8px; }
.timelineItem { display: grid; grid-template-columns: 72px 1fr; gap: 10px; align-items: baseline; }
.timelineYear { font-weight: 700; color: #333; }
.tag {
display: inline-block;
padding: 3px 8px;
border-radius: 999px;
background: #eee;
font-size: 12px;
}
.tag.ok { background: #e6f4ea; color: #137333; }
.cardsGrid {
display: grid;
gap: 12px;
grid-template-columns: 1fr;
}
@media (min-width: 700px) {
.cardsGrid { grid-template-columns: repeat(3, 1fr); }
}
.card {
border: 1px solid #eee;
border-radius: 14px;
padding: 12px;
background: #fff;
}
.cardTitle { margin: 0 0 6px 0; }
.cardPrice { margin: 0 0 10px 0; font-weight: 700; }
.counter {
display: flex;
align-items: center;
gap: 12px;
}
.counter button {
width: 40px;
height: 40px;
border-radius: 10px;
border: 1px solid #ddd;
background: #fff;
cursor: pointer;
font-size: 18px;
}
.counterValue { font-size: 20px; font-weight: 800; min-width: 40px; text-align: center; }
Referência: Wikipedia — React (software): https://en.wikipedia.org/wiki/React_(software)