⚛️

Resumo React

Guia completo de estudo — módulos 07 a 16
11
módulos
16
exercícios
16/06
prova
clique nos módulos para expandir  ·  Ctrl+P para salvar em PDF
Índice
  • → 00  Fundamentos da etapa anterior
  • → 07  HTTP/HTTPS e Postman
  • → 08  Integração de APIs com Axios
  • → 09  async/await, try/catch e LocalStorage
  • → 10  Custom Hooks + useRequestData
  • → 11  React Router completo
  • → 12  Autenticação + JWT
  • → 13  React Forms + useForm
  • → 14  O que é Estado Global?
  • → 15  React Context
  • → 16  Estado Global com Context
Como estudar
  • 📌 Siga a ordem dos módulos
  • ⌨️ Pratique — ler sem codar não fixa
  • 🔍 Função desconhecida? Google / YouTube
  • ↩️ Travou? Volte ao módulo anterior
Bons estudos! 🚀
0 Fundamentos essenciais da etapa anterior useState · componente · map · destructuring · spread · imports clique para abrir
Por que este módulo existe? Os exemplos dos módulos 7–16 usam esses conceitos sem explicá-los. Se algo no código parecer estranho, consulte aqui primeiro.

Componente React — estrutura básica

// Um componente é uma função que retorna JSX (HTML + JS misturados)
// Deve começar com letra maiúscula
function MeuComponente() {
  return (
    <div>
      <h1>Olá mundo</h1>
    </div>
  )
}
export default MeuComponente  // exporta para usar em outro arquivo

// Importando e usando:
import MeuComponente from './MeuComponente'
<MeuComponente />

useState — estado local

O que é estado? Variáveis comuns (let x = 0) não atualizam a tela quando mudam. useState é especial: quando o estado muda, o React re-renderiza o componente automaticamente com o novo valor.
import { useState } from 'react'

function Contador() {
  // useState(valorInicial) retorna [valorAtual, funçãoParaAtualizar]
  const [contador, setContador] = useState(0)
  const [nome, setNome]         = useState("")
  const [lista, setLista]       = useState([])
  const [user, setUser]         = useState({})

  // Para atualizar: SEMPRE usar o setter, nunca modificar direto
  return <button onClick={() => setContador(contador + 1)}>{contador}</button>
}

Props — passando dados entre componentes

// Pai passa dados via atributos (props)
<CartaoUsuario nome="João" idade={21} />

// Filho recebe como parâmetro
function CartaoUsuario(props) {
  return <p>{props.nome} — {props.idade} anos</p>
}

// Ou com destructuring direto (mais comum):
function CartaoUsuario({ nome, idade }) {
  return <p>{nome} — {idade} anos</p>
}

map() — renderizando listas

A prop key é obrigatória em listas. O React usa ela para identificar cada item e saber qual atualizar. Use sempre um ID único — nunca o índice do array se a lista pode mudar de ordem.
const produtos = [
  { id: 1, nome: 'Mouse' },
  { id: 2, nome: 'Teclado' },
]

// map transforma cada item do array em JSX
// key={item.id} é obrigatório — usa o ID único do banco
<ul>
  {produtos.map((item) => (
    <li key={item.id}>{item.nome}</li>
  ))}
</ul>

Renderização condicional

// && → renderiza só se a condição for verdadeira
{isLoading && <p>Carregando...</p>}
{erro && <p>Deu erro</p>}

// Ternário → um ou outro
{logado ? <Dashboard /> : <Login />}

Destructuring — extraindo valores de objetos

// Sem destructuring (verboso)
const nome  = usuario.nome
const email = usuario.email

// Com destructuring (compacto) — mesmo resultado
const { nome, email } = usuario

// Muito usado em eventos de formulário:
const { name, value } = event.target  // pega name e value do input

// E em arrays (useState, hooks customizados):
const [dados, setDados] = useState([])

Spread operator — copiando objetos

// ... (três pontos) copia todas as propriedades de um objeto
const original = { nome: 'João', email: 'j@j.com' }

// Copia tudo e substitui só o email
const atualizado = { ...original, email: 'novo@j.com' }
// → { nome: 'João', email: 'novo@j.com' }

// É exatamente o que o onChange do formulário faz:
// copia o form inteiro e atualiza só o campo que mudou
setForm({ ...form, [name]: value })

Import / Export

// Export padrão — um por arquivo, importado com qualquer nome
export default MinhaFuncao
import MinhaFuncao from './MinhaFuncao'

// Export nomeado — vários por arquivo, importado com chaves {}
export function soma() { ... }
export const PI = 3.14
import { soma, PI } from './utils'

// Biblioteca externa (node_modules)
import axios from 'axios'
import { useState, useEffect } from 'react'

Arrow function — funções curtas

// Função normal
function somar(a, b) { return a + b }

// Arrow function equivalente
const somar = (a, b) => a + b

// Com corpo (mais de uma linha)
const buscar = async () => {
  const res = await axios.get('...')
  setDados(res.data)
}

// Inline em JSX — muito comum
<button onClick={() => setAberto(true)}>Abrir</button>
7 HTTP/HTTPS e Postman métodos · status codes · headers · JSON clique para abrir
⬇ PDF do módulo
Por que estudar isso? React só exibe dados — ele precisa buscá-los de um servidor via HTTP. Entender o protocolo é entender como front-end e back-end se comunicam.

Métodos HTTP — CRUD

MétodoAçãoTem Body?Exemplo de uso
GETBuscar / listarNãoGET /produtos
POSTCriar novoSimPOST /usuarios
PUTAtualizar inteiroSimPUT /usuarios/1
PATCHAtualizar parcialSimPATCH /usuarios/1
DELETEDeletarNãoDELETE /usuarios/1

Status Codes — o que o servidor responde

CódigoSignificado
200OK — sucesso (GET, PUT)
201Created — recurso criado (POST)
204No Content — sucesso sem corpo de resposta (DELETE)
400Bad Request — dados inválidos ou faltando
401Unauthorized — não autenticado (sem token ou token inválido)
403Forbidden — autenticado, mas sem permissão para este recurso
404Not Found — recurso não existe
500Internal Server Error — erro no servidor (bug no back-end)

Anatomia de uma requisição

  • URL / Endpoint: endereço do recurso — ex: https://api.com/usuarios/1
  • Headers: metadados enviados junto — Authorization, Content-Type: application/json
  • Body: dados enviados ao servidor (só POST / PUT / PATCH) — sempre em JSON
  • JSON: formato de dados padrão — { "nome": "João", "idade": 21 }
8 Integração de APIs com Axios GET · POST · PUT · DELETE · headers · Promises clique para abrir
⬇ PDF do módulo
Por que Axios e não o fetch nativo? Axios processa o JSON automaticamente (sem precisar de .json()), trata erros HTTP como exceções e tem menos código repetitivo.

Instalação

npm install axios

Antes de tudo: o que é uma operação assíncrona?

O problema do JavaScript síncrono com APIs Quando o JavaScript faz uma requisição HTTP, isso leva tempo. Se o código esperasse a resposta parado, o browser travaria — sem scroll, sem clique, sem nada. Por isso as chamadas de API são assíncronas: o código continua rodando; quando a resposta chegar, uma função é chamada com o resultado.
O que é uma Promise? Um objeto que representa um valor que ainda não chegou. Todo método do Axios retorna uma Promise. Três estados: pending (aguardando), fulfilled (sucesso) e rejected (erro). Para "pegar" o resultado, existem dois estilos — ambos fazem a mesma coisa:
Estilo 1 — .then() / .catch() (encadeado) Você passa funções de callback. .then(fn) é chamado quando der sucesso. .catch(fn) quando ocorrer erro.

Estilo 2 — async / await (linear) A palavra async marca a função. O await pausa até a Promise resolver, sem travar o browser. Erros capturados com try / catch — como em Java/C#.

GET — Buscar dados (os dois estilos)

import axios from 'axios'

// ── Estilo 1: .then() / .catch() ──────────────────────────────────
// .then  → executado quando a resposta chega com sucesso
// .catch → executado quando ocorre qualquer erro
axios.get('https://api.com/produtos')
  .then((response) => {
    console.log(response.data)       // os dados ficam em response.data
  })
  .catch((error) => {
    console.log(error.response.data)
  })

// ── Estilo 2: async / await ───────────────────────────────────────
// "async" marca a função como assíncrona (obrigatório para usar await)
// "await" pausa aqui até a Promise resolver — sem travar o browser
// "try/catch" captura erros
const buscar = async () => {
  try {
    const response = await axios.get('https://api.com/produtos')
    console.log(response.data)
  } catch (error) {
    console.log(error)
  }
}
Qual usar? Ambos são válidos. .then/.catch é conciso para uma única chamada. async/await é mais claro com múltiplos passos dependentes (ex: fazer login e depois buscar perfil com o token).

POST — Criar (body como 2º argumento)

axios.post('https://api.com/usuarios', {
  nome: 'João',
  email: 'joao@email.com',
  senha: '123456'
}).then((res) => console.log(res.data))

PUT — Atualizar (id na URL, dados no body)

axios.put('https://api.com/usuarios/1', {
  nome: 'João Atualizado',
  email: 'novo@email.com'
}).then((res) => console.log(res.data))

DELETE — Deletar (id na URL, sem body)

axios.delete('https://api.com/usuarios/1')
  .then(() => console.log('Deletado com sucesso'))

Enviando Headers — ex: token JWT

const token = localStorage.getItem('token')

// GET com header de autenticação
axios.get('/api/rota-privada', {
  headers: { Authorization: `Bearer ${token}` }
})

// POST com body + header (body é 2º arg, config é 3º)
axios.post('/api/posts', { titulo: 'Meu post' }, {
  headers: { Authorization: `Bearer ${token}` }
})
Assinatura de cada método:
axios.get(url, config)  |  axios.post(url, body, config)  |  axios.put(url, body, config)  |  axios.delete(url, config)
config = { headers, params, ... }  ·  dados da resposta sempre em response.data

Axios dentro de um componente React

import { useState, useEffect } from 'react'
import axios from 'axios'

export function TelaProdutos() {
  const [produtos, setProdutos] = useState([])

  useEffect(() => {
    axios.get('/api/produtos')
      .then((res) => setProdutos(res.data))
  }, [])  // [] = executa uma única vez ao montar

  return (
    <ul>
      {produtos.map((p) => <li key={p.id}>{p.nome}</li>)}
    </ul>
  )
}
9 async/await, try/catch e LocalStorage assíncrono · erros · persistência no browser clique para abrir
⬇ PDF do módulo
Quando async/await é melhor que .then? Quando há múltiplos passos dependentes: fazer login e, com o token retornado, buscar o perfil. Com .then encadeado vira "callback hell". Com async/await parece código linear.

async/await dentro do useEffect — ATENÇÃO

useEffect não pode ser marcado como async diretamente. Se fosse async, retornaria uma Promise — mas o useEffect espera uma função de cleanup ou undefined. A solução é criar uma função async interna e chamá-la.
// ❌ ERRADO
useEffect(async () => { ... }, [])

// ✅ CORRETO — função async interna
useEffect(() => {
  const buscar = async () => {
    try {
      const res = await axios.get('/api/dados')
      setDados(res.data)
    } catch (err) {
      console.log('Erro:', err)
    }
  }
  buscar()  // define e já chama
}, [])

useEffect — array de dependências

O que é o array de dependências? O segundo argumento diz ao React: "só rode isso de novo se alguma dessas variáveis mudar". Se a variável mudou entre uma renderização e outra, o efeito roda. Se não mudou, React pula.
// Sem array — roda TODA vez que o componente renderizar
// ❌ Quase sempre causa loop infinito:
// setDados() → re-renderiza → useEffect roda → setDados() → loop
useEffect(() => { axios.get('...').then((r) => setDados(r.data)) })

// Array vazio [] — roda UMA VEZ quando o componente aparece na tela
// ✅ Ideal para busca inicial: "ao entrar na tela, carrega os produtos"
useEffect(() => { axios.get('/api/produtos').then(...) }, [])

// [id] — roda na montagem E toda vez que "id" mudar
// ✅ Ideal quando a tela depende de algo da URL ou de um estado:
// ex: usuário clica no produto 1, depois no produto 2 → id muda → re-busca
useEffect(() => { axios.get(`/api/produtos/${id}`).then(...) }, [id])

// [a, b] — roda quando "a" OU "b" mudar
// ✅ Ideal para filtros combinados: re-busca quando qualquer filtro muda
useEffect(() => { axios.get(`/api/produtos?cat=${cat}&ordem=${ordem}`).then(...) }, [cat, ordem])

LocalStorage — persistência no browser

Quando usar: para dados que precisam sobreviver a recarregamentos de página. O estado React some ao fechar/atualizar a aba; o LocalStorage persiste. Mais usado para token de autenticação e preferências do usuário.
// Salvar
localStorage.setItem('chave', 'valor')

// Ler
const valor = localStorage.getItem('chave')  // → "valor" (sempre string)

// Remover
localStorage.removeItem('chave')

// Objetos: converter para string e voltar
localStorage.setItem('user', JSON.stringify({ id: 1, nome: 'João' }))
const user = JSON.parse(localStorage.getItem('user'))
10 Custom Hooks useRequestData · loading/erro · reutilização de lógica clique para abrir
⬇ PDF do módulo
Por que existem? Lógica que usa hooks (useState, useEffect…) não pode ser extraída para uma função comum — o React proibiria. Custom Hooks são funções cujo nome começa com use e podem chamar outros hooks. Use-os para reutilizar lógica entre componentes sem copiar e colar código.

Regras obrigatórias

  • Nome começa com use — obrigatório (ex: useForm, useRequestData)
  • Mesmas regras dos hooks nativos: não chamar dentro de if, loops ou funções aninhadas
  • Crie quando: mesma lógica em 2+ componentes, ou componente fica grande demais

useRequestData(url) — hook genérico para GET

// hooks/useRequestData.js
// Encapsula: chamada axios + estado de loading + estado de erro
import { useState, useEffect } from "react"
import axios from "axios"

export const useRequestData = (url) => {
  const [data, setData]           = useState(undefined)  // undefined = ainda não chegou
  const [isLoading, setIsLoading] = useState(false)
  const [error, setError]         = useState("")

  useEffect(() => {
    setIsLoading(true)
    axios.get(url)
      .then((res) => { setIsLoading(false); setData(res.data) })
      .catch((err) => { setIsLoading(false); setError(err) })
  }, [url])

  return [data, isLoading, error]
}

// Usando em qualquer componente:
const [produtos, isLoading, error] = useRequestData("/api/produtos")
const [usuario, isLoading, error]  = useRequestData("/api/usuario")

Tratando as 4 situações na tela

return (
  <div>
    {isLoading &&
      <p>Carregando...</p>}

    {!isLoading && error &&
      <p>Ocorreu um erro.</p>}

    {!isLoading && data && data.length > 0 && (
      <ul>{data.map((item) => <li key={item.id}>{item.nome}</li>)}</ul>
    )}

    {!isLoading && data && data.length === 0 &&
      <p>Nenhum item encontrado.</p>}
  </div>
)
11 Navegação com React Router Link · NavLink · useNavigate · useParams · useSearchParams clique para abrir
⬇ PDF do módulo
Por que React Router? React cria SPAs — o browser carrega o HTML uma única vez e o JavaScript troca o conteúdo sem recarregar. A URL não muda sozinha. Sem um router, o usuário não pode compartilhar links, usar o botão voltar ou fazer bookmark. O React Router sincroniza URL ↔ componente exibido, sem reload.

Instalação

npm install react-router-dom

Componentes e hooks — visão geral

Componente / HookO que faz
<BrowserRouter>Habilita o roteamento — sempre o mais externo
<Routes>Agrupa as rotas e renderiza apenas a primeira que casar com a URL
<Route path element>Define qual componente renderizar em qual caminho
<Link to>Substitui <a href> — navega sem recarregar
<NavLink to>Igual ao Link, mas adiciona classe active quando a rota está ativa
useNavigate()Retorna função para navegar por código (após submit, login, etc.)
useParams()Lê parâmetros dinâmicos da URL: /produtos/:id
useSearchParams()Lê query string: /produtos?busca=tv&pagina=2

Estrutura base — App.jsx

import { BrowserRouter } from "react-router-dom"

function App() {
  return (
    <BrowserRouter>
      <Menu />       {/* fora do Routes → aparece em todas as páginas */}
      <AppRoutes />
    </BrowserRouter>
  )
}

routes/AppRoutes.jsx

import { Routes, Route } from "react-router-dom"

function AppRoutes() {
  return (
    <Routes>
      <Route path="/"              element={<HomePage />}           />
      <Route path="/sobre"        element={<SobrePage />}          />
      <Route path="/login"        element={<LoginPage />}          />
      <Route path="/produtos"     element={<ProdutosPage />}       />
      <Route path="/produtos/:id" element={<ProdutoDetalhesPage />} />
      <Route path="*"             element={<NotFoundPage />}        />
    </Routes>
  )
}
Por que path="*" é o 404? O * casa com qualquer URL que não casou antes. <Routes> para na primeira rota que bater — por isso * deve ser sempre a última.

Link vs NavLink — quando usar cada um

import { Link, NavLink } from "react-router-dom"

// Link → qualquer lugar fora de menu (cards, botões, listas)
<Link to="/sobre">Sobre</Link>

// NavLink → menus de navegação — adiciona classe "active" na rota atual
<NavLink
  to="/sobre"
  className={({ isActive }) => isActive ? 'menu-ativo' : ''}
>Sobre</NavLink>

<NavLink
  to="/sobre"
  style={({ isActive }) => ({
    color:      isActive ? '#61dafb' : 'white',
    fontWeight: isActive ? 'bold'    : 'normal'
  })}
>Sobre</NavLink>

useNavigate — navegação por código

Quando usar em vez de Link? Quando navegar é consequência de uma ação: login bem-sucedido, formulário salvo, item deletado. Com Link o usuário decide; com useNavigate o código decide — e só navega se tudo deu certo.
const navigate = useNavigate()

navigate("/rota")                        // vai para /rota
navigate(-1)                             // volta (como botão ←)
navigate("/rota", { replace: true })    // vai sem adicionar ao histórico
ChamadaCaso de uso
navigate("/rota")Após login, após salvar formulário
navigate(-1)Botão "Voltar" na tela
navigate("/", { replace: true })Após login — impede voltar para /login

Path Params — useParams()

Por que usar? Sem parâmetros, seria necessário criar uma rota por produto: /produto1, /produto2... Com /:id, uma única rota serve para todos. A URL identifica o recurso — funciona como bookmark e link compartilhável.
// 1. Declarar a rota — dois pontos marcam parâmetro dinâmico
<Route path="/produtos/:id" element={<ProdutoPage />} />

// 2. Ler no componente
const { id } = useParams()   // /produtos/42 → id = "42" (sempre string)

useEffect(() => {
  axios.get(`/api/produtos/${id}`).then((res) => setProduto(res.data))
}, [id])  // re-busca quando o id muda

// 3. Navegar para a rota
<Link to={`/produtos/${produto.id}`}>Ver detalhes</Link>

Search Params — useSearchParams()

Por que não usar estado React para filtros? Estado some ao recarregar a página (F5) ou copiar o link. Search params ficam na URL — /produtos?busca=mouse pode ser compartilhada e sempre mostrará o mesmo resultado. Use para busca, filtros, ordenação, paginação.
// URL: /produtos?busca=mouse&pagina=2
const [searchParams] = useSearchParams()
const busca  = searchParams.get("busca")   // → "mouse" | null
const pagina = searchParams.get("pagina")  // → "2"
Path Params /produtos/42Search Params /produtos?busca=tv
IdentificaRecurso único e específicoFiltro, configuração ou estado
HookuseParams()useSearchParams()
Declarar na rotaSim: path="/produtos/:id"Não — lido direto da URL
ExemplosDetalhe de produto, perfil de usuárioBusca, filtros, ordenação, paginação

Organização de arquivos recomendada

src/
  ├── components/    → Menu, Button, Card (reutilizáveis)
  ├── pages/         → HomePage, LoginPage, ProdutosPage...
  ├── routes/        → AppRoutes.jsx, coordinator.js
  ├── hooks/         → useRequestData.js, useForm.js
  ├── contexts/      → GlobalState.js, GlobalStateContext.js
  ├── App.jsx
  └── main.jsx

Coordinator — centralizando as strings de rota

// routes/coordinator.js
export function goToHome(navigate)               { navigate("/") }
export function goToLogin(navigate)              { navigate("/login") }
export function goToProductDetails(navigate, id) { navigate(`/produtos/${id}`) }
export function goBack(navigate)                 { navigate(-1) }
Deploy — problema do refresh (F5) em SPA: O servidor procura um arquivo físico chamado /produtos — que não existe. Retorna 404. A solução é configurar o servidor para redirecionar tudo para index.html; o React Router assume o controle a partir daí.
12 Autenticação em Aplicações React JWT · Cookies vs LocalStorage · login · rota protegida · logout clique para abrir
⬇ PDF do módulo
Fluxo geral: usuário faz login → back-end valida → retorna token → front salva o token → envia em cada requisição protegida → back-end valida e libera.

JWT — JSON Web Token

  • String com 3 partes separadas por ponto: Header.Payload.Assinatura
  • O Payload contém: id, email, role (permissão), data de expiração
  • O back-end assina com chave secreta — se alguém alterar o token, a assinatura fica inválida
  • Não precisa de sessão no servidor — o token carrega tudo

Cookies vs LocalStorage

CookiesLocalStorage
Quem defineBack-end (header Set-Cookie)Front-end (JavaScript)
Envio automáticoSim — browser envia em toda requisição do mesmo domínioNão — adicionado manualmente nos headers
Como usarAutomáticoAuthorization: Bearer TOKEN

Fluxo completo com LocalStorage

// 1. LOGIN — receber e salvar o token
const handleLogin = async () => {
  try {
    const res = await axios.post('/api/login', { email, senha })
    localStorage.setItem('token', res.data.token)
    navigate('/', { replace: true })  // replace → sem volta para /login
  } catch (err) { alert('Credenciais inválidas') }
}

// 2. REQUISIÇÃO PROTEGIDA — enviar token no header
const token = localStorage.getItem('token')
axios.get('/api/meus-dados', {
  headers: { Authorization: `Bearer ${token}` }
})

// 3. ROTA PROTEGIDA — redirecionar se não tiver token
useEffect(() => {
  if (!localStorage.getItem('token')) navigate('/login')
}, [])

// 4. LOGOUT — apagar e redirecionar
const logout = () => {
  localStorage.removeItem('token')
  navigate('/login')
}
13 React + Forms onSubmit · onChange unificado · validações · REGEX · useForm clique para abrir
⬇ PDF do módulo
Por que usar a tag <form>? Ela centraliza o submit em um evento só, permite que Enter dispare o submit, e habilita validações nativas do browser com required, type="email" e pattern.

Formulário completo com handler unificado

function Login() {
  // Um objeto para todos os campos — não um useState por campo
  const [form, setForm] = useState({ email: "", password: "" })

  // Um único handler para todos os inputs
  // event.target.name = qual campo | event.target.value = o que foi digitado
  const onChange = (event) => {
    const { name, value } = event.target
    setForm({ ...form, [name]: value })  // [name] = chave dinâmica
  }

  const handleSubmit = (event) => {
    event.preventDefault()  // cancela o reload padrão do HTML — SEMPRE necessário
    axios.post('/api/login', form).then(...)
  }

  return (
    <form onSubmit={handleSubmit}>  {/* onSubmit na <form>, não onClick no botão */}
      <input name="email"    value={form.email}    onChange={onChange} type="email"    required />
      <input name="password" value={form.password} onChange={onChange} type="password" required />
      <button type="submit">Entrar</button>
    </form>
  )
}
event.preventDefault(): o comportamento padrão do browser ao submeter um form HTML é recarregar a página inteira — um resquício do HTML clássico. Em SPA isso destruiria todo o estado. preventDefault() cancela esse comportamento.
Chave dinâmica { [name]: value }: os colchetes fazem o JavaScript usar o valor da variável name como chave. Se name = "email", gera { email: value }. É isso que permite um único onChange para vários campos.

Validações HTML nativas

AtributoO que validaExemplo
requiredCampo obrigatório<input required />
type="email"Formato de e-mail<input type="email" />
type="number"Somente números<input type="number" />
min / maxValor mínimo/máximomin="18" max="100"
minLengthMínimo de caracteresminLength="3"
patternExpressão regular customizadapattern="[0-9]{8}"

REGEX — padrões para o atributo pattern

<input pattern="[A-Za-z]{3,}"       />  // letras (maiú ou minú), mínimo 3
<input pattern="[0-9]{8}"          />  // exatamente 8 dígitos
<input pattern=".{6,}"             />  // qualquer coisa, mínimo 6 chars
<input pattern="[0-9]{5}-[0-9]{3}" />  // CEP: 12345-678
SímboloSignificaExemplo
[A-Z]Uma letra maiúscula[A-Z]{3} = 3 maiúsculas
[a-z]Uma letra minúscula
[0-9]Um dígito[0-9]{4} = 4 dígitos
{n}Exatamente n vezes[0-9]{8}
{n,}n ou mais vezes.{6,} = mín 6
{n,m}Entre n e m vezes[a-z]{3,10}
.Qualquer caractere.{8,} = mín 8

Custom Hook useForm()

Por que extrair? A lógica (estado + onChange unificado) vai se repetir em toda tela com inputs: Login, Cadastro, Editar perfil... O hook encapsula uma vez e serve para todos.
// hooks/useForm.js
const useForm = (initialState) => {
  const [form, setForm] = useState(initialState)
  const onChange = (event) => {
    const { name, value } = event.target
    setForm({ ...form, [name]: value })
  }
  return [form, onChange]
}

// Usando:
const [form, onChange] = useForm({ email: "", password: "" })
// Cada input: name="campo"  value={form.campo}  onChange={onChange}
14 O que é um Estado Global? Props Drilling · Redux · MobX · Context API clique para abrir
⬇ PDF do módulo

Problemas com estados locais em apps grandes

ProblemaO que acontece na prática
Dados espalhadosCada componente tem estado isolado — difícil coordenar
Responsabilidade erradaComponente de navegação gerenciando dados do carrinho
Fonte de verdade duplaMesmo dado em dois lugares → pode desincronizar
Props DrillingUma prop atravessa 3-4 componentes que não precisam dela

Props Drilling — visualizando o problema

// ❌ Filho1 e Filho2 recebem "carrinho" só para repassar — não usam
<App carrinho={carrinho}>
  <Filho1 carrinho={carrinho}>        {// não usa, só repassa}
    <Filho2 carrinho={carrinho}>      {// não usa, só repassa}
      <Filho3 carrinho={carrinho} />  {// usa de verdade}
    </Filho2>
  </Filho1>
</App>

Estado Global — como deve funcionar

  • Uma camada de dados única, acessada diretamente por qualquer componente
  • Fluxo: API ↔ Estado Global ↔ Componentes (sem props)
  • Componentes não chamam a API diretamente — pedem ao estado global

Opções de implementação

OpçãoQuando usar
ReduxApps muito grandes com muitos desenvolvedores
MobXEquipes que preferem orientação a objetos
Context API (nativa)Apps médios — sem instalar nada extra
15 React Context createContext · Provider · useContext · reatividade clique para abrir
⬇ PDF do módulo
Por que Context e não uma variável global comum? Uma variável let dados = [] não é reativa — mudar ela não re-renderiza nada. O Context é integrado ao React: quando o value do Provider muda, todos os consumidores re-renderizam automaticamente.

Os 3 passos — criar, fornecer e consumir

import React, { useState, useContext } from "react"

// PASSO 1: Criar o contexto (geralmente em arquivo separado)
export const MeuContexto = React.createContext()

// PASSO 2: Provider — envolve quem vai precisar dos dados
// Qualquer nível dentro dele pode acessar o "value"
function App() {
  const [cor, setCor] = useState("azul")
  return (
    <MeuContexto.Provider value={{ cor, setCor }}>
      <ComponenteA />
      <ComponenteB />
    </MeuContexto.Provider>
  )
}

// PASSO 3: Consumer — acessa em qualquer nível, sem prop drilling
function ComponenteB() {
  const { cor, setCor } = useContext(MeuContexto)  // recebe o value
  return <p>Cor: {cor}</p>
}

Onde o Context aparece na prática

  • Dados do usuário logado: nome, foto, permissões em qualquer tela
  • Tema visual (dark/light) — o ThemeProvider do Material UI é um Context
  • Idioma — textos traduzidos disponíveis globalmente
  • O próprio <BrowserRouter> usa Context para que useNavigate e useParams funcionem em qualquer lugar
Quando NÃO usar: quando o dado percorre 1-2 níveis apenas — props são mais simples. Context tem custo: todo consumidor re-renderiza quando o value muda.
16 Estado Global com Context GlobalState · states · setters · requests · arquitetura completa clique para abrir
⬇ PDF do módulo
A ideia: um componente GlobalState centraliza todos os estados e funções de requisição, e os distribui via Context para qualquer componente — sem props drilling.

Os 3 arquivos da arquitetura

ArquivoPapel
GlobalStateContext.jsCria e exporta o objeto Context (1 linha)
GlobalState.jsTodos os estados, funções de API e o Provider
App.jsxUsa <GlobalState> como wrapper mais externo

GlobalStateContext.js

import React from "react"
const GlobalStateContext = React.createContext()
export default GlobalStateContext

GlobalState.js — coração do sistema

import React, { useState } from "react"
import axios from "axios"
import GlobalStateContext from "./GlobalStateContext"

const GlobalState = (props) => {

  // ── estados ────────────────────────────────────────────
  const [produtos, setProdutos] = useState([])
  const [usuario, setUsuario]   = useState({})
  const [carrinho, setCarrinho] = useState([])

  // ── requisições ────────────────────────────────────────
  const getProdutos = () => {
    axios.get('/api/produtos').then((res) => setProdutos(res.data))
  }
  const getUsuario = () => {
    axios.get('/api/usuario').then((res) => setUsuario(res.data))
  }

  // ── 3 grupos para facilitar o consumo ─────────────────
  const states   = { produtos, usuario, carrinho }
  const setters  = { setProdutos, setUsuario, setCarrinho }
  const requests = { getProdutos, getUsuario }

  return (
    <GlobalStateContext.Provider value={{ states, setters, requests }}>
      {props.children}
    </GlobalStateContext.Provider>
  )
}
export default GlobalState

App.jsx — GlobalState como wrapper mais externo

function App() {
  return (
    <GlobalState>
      <BrowserRouter>
        <Menu />
        <AppRoutes />
      </BrowserRouter>
    </GlobalState>
  )
}

Consumindo em qualquer componente

import { useContext, useEffect } from "react"
import GlobalStateContext from "../contexts/GlobalStateContext"

function TelaProdutos() {
  const { states, setters, requests } = useContext(GlobalStateContext)

  const { produtos }    = states
  const { getProdutos } = requests

  useEffect(() => { getProdutos() }, [])

  return (
    <ul>{produtos.map((p) => <li key={p.id}>{p.nome}</li>)}</ul>
  )
}