UC00621

Frameworks JavaScript — React

Componentes, estado, hooks, deploy

Curso profissional · 25h · Frontend moderno

Plano

  1. O que é React e porquê
  2. Setup: Vite
  3. JSX e componentes
  4. Props e composição
  5. Estado (useState)
  6. Eventos e formulários
  7. Efeitos (useEffect)
  8. Listas e keys
  9. Routing (React Router)
  10. Deploy

Bloco 1 · Introdução

Porquê React?

  • Componentes reutilizáveis = código DRY.
  • Estado reactivo = UI actualiza automaticamente.
  • Ecossistema enorme (libraries, jobs).
  • Performance (Virtual DOM).
  • Usado por: Facebook, Netflix, Airbnb, Vercel.

Alternativas: Vue, Svelte, Angular.

Vanilla vs React

// Vanilla JS — manual
document.getElementById("count").textContent = count;

// React — declarativo
function Counter() {
  const [count, setCount] = useState(0);
  return <p>{count}</p>;
}

React = "descreve o que queres", não "como o fazer passo a passo".

Setup com Vite

npm create vite@latest minha-app -- --template react
cd minha-app
npm install
npm run dev

Abre http://localhost:5173

Vite = bundler moderno (rápido, simples).

Estrutura do projecto

minha-app/
├── public/
├── src/
│   ├── App.jsx
│   ├── main.jsx
│   ├── App.css
│   └── components/
├── index.html
├── package.json
└── vite.config.js

Tudo começa em main.jsx → renderiza <App />.

Bloco 2 · JSX

O que é JSX

// Não é HTML, é JavaScript
const elemento = <h1>Olá mundo</h1>;

// Pode misturar variáveis
const nome = "Ana";
const saudacao = <h1>Olá, {nome}!</h1>;

// Atributos em camelCase
<div className="card" onClick={handleClick}>
  <img src={url} alt={descricao} />
</div>

Importante: classclassName, forhtmlFor.

Regras JSX

// ❌ Múltiplos elementos top-level
return (
  <h1>Título</h1>
  <p>Texto</p>
);

// ✅ Wrap em fragment ou div
return (
  <>
    <h1>Título</h1>
    <p>Texto</p>
  </>
);

// ✅ Self-closing tags
<img src="..." />
<br />

Bloco 3 · Componentes

Componente funcional

// Definição
function Saudacao() {
  return <h1>Olá!</h1>;
}

// Uso
function App() {
  return (
    <div>
      <Saudacao />
      <Saudacao />
    </div>
  );
}

Convenção: nome do componente em PascalCase.

Props

// Receber props
function Card({ titulo, descricao }) {
  return (
    <div className="card">
      <h2>{titulo}</h2>
      <p>{descricao}</p>
    </div>
  );
}

// Passar props
<Card 
  titulo="React" 
  descricao="Framework JavaScript" 
/>

Props são imutáveis.

Children

function Card({ children }) {
  return <div className="card">{children}</div>;
}

// Uso
<Card>
  <h2>Título</h2>
  <p>Conteúdo personalizado</p>
</Card>

children = tudo entre as tags de abertura/fechamento.

Bloco 4 · Estado

useState

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Contador: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        +1
      </button>
    </div>
  );
}

setCount triggers re-render do componente.

Estado com objectos

const [user, setUser] = useState({
  nome: "",
  email: "",
});

// Update imutável (spread)
setUser({
  ...user,
  nome: "Ana"
});

// Update baseado em estado anterior
setCount(prev => prev + 1);

Nunca mutar directamente o estado!

Renderização condicional

function Welcome({ user }) {
  if (!user) {
    return <p>Login necessário</p>;
  }
  return <h1>Olá, {user.nome}</h1>;
}

// Inline com &&
{isLoggedIn && <Dashboard />}

// Ternário
{isLoading ? <Spinner /> : <Content />}

Bloco 5 · Eventos

Handlers

function Form() {
  const [nome, setNome] = useState("");
  
  const handleChange = (e) => {
    setNome(e.target.value);
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("Submetido:", nome);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input value={nome} onChange={handleChange} />
      <button type="submit">Enviar</button>
    </form>
  );
}

Controlled inputs

function Login() {
  const [form, setForm] = useState({
    email: "",
    password: ""
  });
  
  const update = (campo) => (e) => {
    setForm({ ...form, [campo]: e.target.value });
  };
  
  return (
    <form>
      <input value={form.email} onChange={update("email")} />
      <input value={form.password} onChange={update("password")} />
    </form>
  );
}

Bloco 6 · useEffect

Side effects

import { useEffect, useState } from "react";

function Clock() {
  const [time, setTime] = useState(new Date());
  
  useEffect(() => {
    const timer = setInterval(() => {
      setTime(new Date());
    }, 1000);
    
    // Cleanup
    return () => clearInterval(timer);
  }, []);  // [] = correr apenas no mount
  
  return <p>{time.toLocaleTimeString()}</p>;
}

Fetch de dados

function Users() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    fetch("https://api.github.com/users")
      .then(r => r.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      });
  }, []);
  
  if (loading) return <p>A carregar...</p>;
  
  return (
    <ul>
      {users.map(u => <li key={u.id}>{u.login}</li>)}
    </ul>
  );
}

Bloco 7 · Listas

map() e keys

const tarefas = [
  { id: 1, texto: "Estudar React" },
  { id: 2, texto: "Fazer projecto" },
];

function Lista() {
  return (
    <ul>
      {tarefas.map(t => (
        <li key={t.id}>{t.texto}</li>
      ))}
    </ul>
  );
}

key = único e estável (preferir ID, não index).

Adicionar/remover

function TodoList() {
  const [todos, setTodos] = useState([]);
  
  const add = (texto) => {
    setTodos([...todos, { id: Date.now(), texto }]);
  };
  
  const remove = (id) => {
    setTodos(todos.filter(t => t.id !== id));
  };
  
  return (
    <ul>
      {todos.map(t => (
        <li key={t.id}>
          {t.texto}
          <button onClick={() => remove(t.id)}>X</button>
        </li>
      ))}
    </ul>
  );
}

Bloco 8 · Routing

React Router

npm install react-router-dom
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/sobre">Sobre</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/sobre" element={<Sobre />} />
        <Route path="/user/:id" element={<User />} />
      </Routes>
    </BrowserRouter>
  );
}

Parâmetros

import { useParams, useNavigate } from "react-router-dom";

function User() {
  const { id } = useParams();
  const navigate = useNavigate();
  
  return (
    <div>
      <h1>User {id}</h1>
      <button onClick={() => navigate("/")}>
        Voltar
      </button>
    </div>
  );
}

Bloco 9 · Deploy

Build de produção

npm run build

# Cria pasta dist/ com ficheiros optimizados

dist/ = HTML, CSS, JS minificados prontos a servir.

Vercel (recomendado)

npm i -g vercel
vercel

Ou via dashboard:

  1. Push repo no GitHub.
  2. Importar no vercel.com.
  3. Deploy automático em cada push.

Outras opções: Netlify, GitHub Pages, Cloudflare Pages.

Boas práticas

  • Componentes pequenos (< 100 linhas).
  • Separar lógica (custom hooks).
  • PropTypes ou TypeScript para tipos.
  • Não mutar estado directamente.
  • Sempre key em listas.
  • Loading + error states em fetch.
  • Acessibilidade (semantic JSX).

UC00621 · resumo

  • React = componentes reutilizáveis + estado reactivo.
  • JSX = JS que parece HTML.
  • Props = dados de pai → filho (imutáveis).
  • useState = estado local que triggers re-render.
  • useEffect = side effects (fetch, timers, subscriptions).
  • map() + key para listas.
  • React Router para multi-página.
  • Vercel/Netlify para deploy rápido.
  • Base para Next.js, React Native, e ecossistema moderno.

NOTAS DO PROFESSOR 📖 Porquê uma framework de componentes Importa que os formandos percebam o problema que o React resolve: à medida que uma interface cresce, manipular o DOM à mão torna-se ingerível. Componentes reutilizáveis e estado reactivo são a resposta. Mencionar que dominar os conceitos do React transfere-se para Vue ou Svelte motiva a aprendizagem. 🗣️ Pontos a desenvolver oralmente • Descrever a dor de manter UI complexa com JavaScript puro. • Explicar o que é estado reactivo: a UI reflete sempre os dados. • Posicionar o React no ecossistema e referir as alternativas.

NOTAS DO PROFESSOR 📖 Declarativo vs imperativo Esta é a mudança mental mais importante: em vez de dar instruções passo a passo de como atualizar o ecrã (imperativo), descreve-se o resultado desejado e o React trata de o aplicar (declarativo). Quem vem de JavaScript puro precisa de tempo para esta transição de pensamento. 🗣️ Pontos a desenvolver oralmente • Comparar o exemplo vanilla e o React lado a lado. • Explicar que no React não se toca diretamente no DOM, deixa-se o React fazê-lo. • Reforçar que a UI é uma função do estado.

NOTAS DO PROFESSOR 📖 Arrancar um projeto em segundos O Vite cria o esqueleto do projeto e fornece um servidor de desenvolvimento com recarga instantânea (hot reload). Vale a pena correr este comando em conjunto na sala e abrir o navegador para ver o resultado. Perceber que `npm install` descarrega as dependências e `npm run dev` arranca o servidor é fundamental. 🗣️ Pontos a desenvolver oralmente • Demonstrar o hot reload editando um ficheiro e vendo o navegador atualizar. • Explicar o papel do `package.json` e da pasta `node_modules`. • Distinguir o servidor de desenvolvimento do build de produção.

NOTAS DO PROFESSOR 📖 Saber onde vive cada coisa Conhecer a estrutura padrão evita os formandos andarem perdidos: `main.jsx` é o ponto de entrada que monta a aplicação, `App.jsx` é o componente raiz e a pasta `components` agrupa os componentes reutilizáveis. Esta organização repete-se em quase todos os projetos React. 🗣️ Pontos a desenvolver oralmente • Seguir o fluxo do `index.html` ao `main.jsx` e ao `<App />`. • Justificar a pasta `components` para organização à medida que o projeto cresce. • Mostrar onde colocar ficheiros CSS e assets.

NOTAS DO PROFESSOR 📖 JSX é JavaScript disfarçado de HTML O JSX parece HTML mas compila para chamadas JavaScript. As chavetas `{}` são a porta para inserir qualquer expressão JS dentro do markup. As diferenças face ao HTML (`className`, `htmlFor`, camelCase) existem porque os atributos viram propriedades de objetos JS, e palavras como `class` são reservadas. 🗣️ Pontos a desenvolver oralmente • Demonstrar a inserção de variáveis e expressões com `{}`. • Explicar porque `class` se torna `className`. • Avisar que dentro de `{}` só vão expressões, não instruções como `if`.

NOTAS DO PROFESSOR 📖 As regras que evitam erros comuns Estas regras causam muitos erros a quem começa: um componente tem de devolver um único elemento de topo (daí os fragments `<>...</>`), e todas as tags têm de ser fechadas, mesmo as que em HTML não fechavam. Convém mostrar a mensagem de erro que aparece quando se esquecem. 🗣️ Pontos a desenvolver oralmente • Provocar de propósito o erro de múltiplos elementos top-level e ler a mensagem. • Explicar o fragment como forma de agrupar sem criar uma div extra. • Reforçar o self-closing obrigatório em `<img>`, `<br>`, etc.

NOTAS DO PROFESSOR 📖 O componente é uma função que devolve JSX No React moderno, um componente é simplesmente uma função que devolve markup. Pode ser usado como uma tag (`<Saudacao />`) e reutilizado quantas vezes se quiser. A convenção PascalCase é obrigatória: o React distingue componentes (maiúscula) de tags HTML (minúscula) pela primeira letra. 🗣️ Pontos a desenvolver oralmente • Mostrar a reutilização chamando o mesmo componente várias vezes. • Explicar porque o nome tem de começar por maiúscula. • Reforçar a ideia de compor interfaces a partir de peças pequenas.

NOTAS DO PROFESSOR 📖 Passar dados de pai para filho As props são o mecanismo de comunicação descendente: o componente-pai passa valores e o filho recebe-os como argumentos. A desestruturação `{ titulo, descricao }` torna o código mais legível. O ponto crítico é a imutabilidade — um componente nunca deve alterar as suas próprias props. 🗣️ Pontos a desenvolver oralmente • Mostrar a mesma `Card` reutilizada com props diferentes. • Explicar a desestruturação das props na assinatura da função. • Reforçar que props fluem só num sentido (pai para filho).

NOTAS DO PROFESSOR 📖 Componentes que envolvem outros A prop especial `children` permite criar componentes-contentor que envolvem conteúdo arbitrário, como cartões, modais ou layouts. É a base da composição em React: em vez de configurar tudo por props, passa-se markup completo entre as tags. Um padrão poderoso e muito usado. 🗣️ Pontos a desenvolver oralmente • Distinguir `children` das props normais. • Dar exemplos práticos: um Card, um Modal, um Layout reutilizável. • Mostrar como a composição evita componentes com dezenas de props.

NOTAS DO PROFESSOR 📖 O coração da reactividade O `useState` é o hook fundamental: devolve o valor atual e uma função para o atualizar. A chave a fixar é que alterar o estado com `setCount` faz o React re-renderizar o componente automaticamente — não se toca no DOM à mão. Atribuir diretamente à variável não funcionaria. 🗣️ Pontos a desenvolver oralmente • Explicar a desestruturação do array `[valor, setValor]`. • Demonstrar que `count = count + 1` não atualiza a UI, só `setCount` o faz. • Introduzir a ideia de re-render como reação à mudança de estado.

NOTAS DO PROFESSOR 📖 Atualizar estado de forma imutável Quando o estado é um objeto, não se altera uma propriedade diretamente: cria-se um novo objeto com o spread `...` e a mudança aplicada. O React deteta a mudança por comparação de referência, daí a necessidade de um objeto novo. A forma funcional `prev => prev + 1` é mais segura quando o novo valor depende do anterior. 🗣️ Pontos a desenvolver oralmente • Demonstrar porque mutar o objeto não dispara re-render. • Explicar o operador spread aplicado a estado. • Justificar a forma `setCount(prev => ...)` em atualizações rápidas sucessivas.

NOTAS DO PROFESSOR 📖 Mostrar UI diferente conforme o estado A renderização condicional permite que o mesmo componente apresente coisas diferentes consoante os dados: um spinner enquanto carrega, conteúdo quando termina. Os padrões `&&` (mostrar se verdadeiro) e o ternário (escolher entre dois) são idiomáticos. Convém alertar para a armadilha do `&&` com valores numéricos. 🗣️ Pontos a desenvolver oralmente • Mostrar os três padrões: return antecipado, `&&` e ternário. • Avisar que `0 && <X/>` renderiza o 0 — usar booleanos explícitos. • Ligar a renderização condicional aos estados de loading e erro.

NOTAS DO PROFESSOR 📖 Reagir a interações do utilizador Os eventos no React usam camelCase (`onClick`, `onChange`, `onSubmit`) e recebem funções como handlers. O `e.preventDefault()` é essencial nos formulários para impedir o recarregamento da página, comportamento padrão do HTML. Convém mostrar o objeto do evento e como aceder ao valor digitado. 🗣️ Pontos a desenvolver oralmente • Explicar porque `onSubmit` sem `preventDefault` recarrega a página. • Mostrar `e.target.value` para obter o que o utilizador escreveu. • Distinguir passar a função (`onClick={handle}`) de a invocar (`onClick={handle()}`).

NOTAS DO PROFESSOR 📖 O formulário controlado pelo estado Num input controlado, o estado do React é a fonte única de verdade: o valor mostrado vem do estado e cada tecla atualiza-o via `onChange`. Isto dá controlo total para validar ou transformar o input. O padrão de uma função genérica por campo evita repetir handlers, mas convém primeiro mostrar a versão simples. 🗣️ Pontos a desenvolver oralmente • Explicar o ciclo: estado → value → onChange → setState → re-render. • Contrastar input controlado com input não-controlado. • Decompor a função `update(campo)` que devolve um handler.

NOTAS DO PROFESSOR 📖 Efeitos secundários fora do render O `useEffect` serve para tudo o que não é renderizar puro: timers, subscrições, pedidos a APIs. O array de dependências controla quando corre — `[]` significa apenas no mount. A função de cleanup (o `return`) é crucial para evitar fugas, como timers que continuam a correr depois do componente desaparecer. 🗣️ Pontos a desenvolver oralmente • Explicar o significado do array vazio `[]` como dependências. • Sublinhar a importância do cleanup para libertar recursos. • Avisar para o problema de esquecer dependências e obter dados desatualizados.

NOTAS DO PROFESSOR 📖 Buscar dados de uma API Este é o padrão mais comum em aplicações reais: ao montar, o componente pede dados a uma API e atualiza o estado com a resposta. Gerir o estado de loading é essencial para dar feedback ao utilizador. Convém mencionar que falta aqui o tratamento de erros, que se deve sempre acrescentar. 🗣️ Pontos a desenvolver oralmente • Seguir o fluxo: efeito no mount, fetch, setState, re-render. • Sublinhar a importância do estado de loading para a experiência. • Apontar que em produção se deve adicionar tratamento de erro e estado de erro.

NOTAS DO PROFESSOR 📖 Transformar dados em elementos O método `map` é a forma idiomática de renderizar listas: transforma cada item de dados num elemento JSX. A prop `key` não é decorativa — o React usa-a para identificar cada item e atualizar a lista de forma eficiente. Usar o índice como key causa bugs quando a lista muda de ordem. 🗣️ Pontos a desenvolver oralmente • Explicar para que serve a `key` internamente no React. • Demonstrar o problema de usar o índice como key ao reordenar. • Mostrar o aviso da consola quando a key falta.

NOTAS DO PROFESSOR 📖 Alterar listas no estado sem mutar Para adicionar, cria-se um novo array com spread (`[...todos, novo]`); para remover, usa-se `filter`. Em ambos os casos gera-se um array novo em vez de alterar o existente, respeitando a imutabilidade que o React exige. O `Date.now()` serve aqui de id simples e único. 🗣️ Pontos a desenvolver oralmente • Demonstrar `filter` para remover e spread para adicionar. • Reforçar que `push` mutaria o array e não dispararia re-render. • Mostrar a passagem do id ao handler de remoção via arrow function.

NOTAS DO PROFESSOR 📖 Várias páginas numa SPA O React Router permite ter múltiplas vistas numa aplicação de página única, trocando componentes consoante o URL sem recarregar a página. O `<Link>` substitui o `<a>` para navegar sem refresh, e as `<Route>` mapeiam caminhos a componentes. O `:id` é um segmento dinâmico. 🗣️ Pontos a desenvolver oralmente • Explicar o conceito de SPA e porque o URL muda sem recarregar. • Distinguir `<Link>` de `<a>` e o efeito no desempenho. • Introduzir as rotas dinâmicas com `:id`.

NOTAS DO PROFESSOR 📖 Ler o URL e navegar por código O hook `useParams` extrai os segmentos dinâmicos do URL (o `:id` definido na rota), permitindo que o componente saiba o que mostrar. O `useNavigate` permite mudar de página em resposta a uma ação, como após submeter um formulário. São as ferramentas que ligam a navegação à lógica da aplicação. 🗣️ Pontos a desenvolver oralmente • Ligar o `:id` da rota ao valor obtido por `useParams`. • Mostrar um caso de `useNavigate` (redirecionar após login). • Reforçar que estes são hooks e seguem as regras dos hooks.

NOTAS DO PROFESSOR 📖 Do código de desenvolvimento ao site real O `npm run build` transforma o projeto em ficheiros estáticos otimizados (minificados) na pasta `dist`. Convém clarificar a diferença face ao servidor de desenvolvimento: o build é o que se publica, sem hot reload nem ferramentas de debug. É um passo obrigatório antes de qualquer deploy. 🗣️ Pontos a desenvolver oralmente • Distinguir o modo de desenvolvimento do build de produção. • Explicar o que é minificação e porque reduz o tempo de carregamento. • Mostrar o conteúdo da pasta `dist` gerada.

NOTAS DO PROFESSOR 📖 Publicar com deploy contínuo Plataformas como a Vercel automatizam o deploy: ligam-se ao repositório GitHub e publicam a cada push, sem gerir servidores. Este fluxo de deploy contínuo é o padrão moderno e dá aos formandos a satisfação de ver o seu projeto online com um URL real para o portefólio. 🗣️ Pontos a desenvolver oralmente • Demonstrar o fluxo push → deploy automático. • Sublinhar o valor de ter um URL público para mostrar no CV. • Referir que estas plataformas têm planos gratuitos para projetos pequenos.

NOTAS DO PROFESSOR 📖 Hábitos que distinguem código profissional Estas práticas resultam de problemas reais: componentes grandes tornam-se ingeríveis, mutar estado causa bugs subtis, e esquecer estados de loading/erro frustra utilizadores. Convém apresentá-las como hábitos a adotar desde o primeiro projeto, não como refinamentos opcionais. 🗣️ Pontos a desenvolver oralmente • Justificar o limite de tamanho dos componentes com a manutenibilidade. • Introduzir os custom hooks como forma de extrair e reutilizar lógica. • Reforçar a acessibilidade usando JSX semântico em vez de divs para tudo.

NOTAS DO PROFESSOR 📖 Consolidar o modelo mental do React Este resumo fecha o arco: componentes, props, estado, efeitos, listas, routing e deploy. Vale a pena reforçar que o modelo mental — UI como função do estado — é o que se transfere para Next.js e React Native. Os hooks aprendidos aqui são a base de quase tudo no React moderno. 🗣️ Pontos a desenvolver oralmente • Pedir aos formandos que liguem cada conceito a algo que construíram. • Apontar Next.js (web full-stack) e React Native (mobile) como próximos passos. • Reforçar que a prática num projeto próprio é o que fixa estes conceitos.