Pular para o conteúdo
murad.guide

Aplicações Web

Capítulo 5

React: efeitos e dados locais

3 min de leitura 451 palavras 1 gravura

Neste capítulo você vai carregar o catálogo JSON com useEffect e fetch local. O projeto-fio é o Ateliê Boa Viagem, ateliê digital fictício em Boa Viagem, Recife.

Seu ponto de partida

Use o exemplo 05-react-efeitos do pacote anexo e copie inicio/ para uma pasta de prática fora do original. A raiz do exemplo é a referência completa desta etapa.

Use servidor só em 127.0.0.1 quando o README do exemplo pedir HTTP local. Abrir ou testar não publica nada.

Como praticar

Leia → copie ou digite → mude uma coisa → preveja → salve → recarregue → confira. Restaure cada experiência antes da próxima. Faça as atividades antes de abrir as respostas comentadas.

useEffect para efeitos colaterais

Buscar dados, assinar eventos ou sincronizar com o documento são efeitos. O array de dependências controla quando o efeito roda de novo.

Faça na sua cópia

Confira o trecho no contexto do exemplo antes de mudar.

React.useEffect(() => {
  fetch('catalogo.json')
    .then((r) => r.json())
    .then(setItens);
}, []);

Mude uma coisa e preveja

Altere um título em catalogo.json e recarregue.

Anote o que espera observar antes de salvar e recarregar.

Recarregue e confira

A lista reflete o JSON.

Se não acontecer

Use HTTP local; file:// costuma bloquear fetch.

Ateliê Boa Viagem — vitrine

Estados de carregamento e erro

Mostre carregando, sucesso e falha. O conteúdo principal do Ateliê não deve sumir sem explicação.

Faça na sua cópia

Confira o trecho no contexto do exemplo antes de mudar.

const [status, setStatus] = React.useState('carregando');

Mude uma coisa e preveja

Renomeie catalogo.json e observe a falha.

Anote o que espera observar antes de salvar e recarregar.

Recarregue e confira

A interface avisa o erro. Restaure o nome.

Se não acontecer

Trate .catch e defina status erro.

Não publique dados reais

Os JSON do volume são fictícios. Não coloque e-mails ou telefones verdadeiros nos exemplos.

Faça na sua cópia

Confira o trecho no contexto do exemplo antes de mudar.

{
  "oficinas": [{ "id": 1, "nome": "Serigrafia da orla" }]
}

Mude uma coisa e preveja

Troque o nome da oficina no JSON.

Anote o que espera observar antes de salvar e recarregar.

Recarregue e confira

A vitrine atualiza após recarregar.

Se não acontecer

Confirme o servidor em 127.0.0.1.

Atividades

Atividade 1

Por que fetch de JSON local pede HTTP?

Atividade 2

O que significa o array vazio no useEffect?

Atividade 3

Quais três status de interface este volume pede?

Respostas comentadas

Resposta da atividade 1

Política do navegador para file:// e módulos/recursos.

Resposta da atividade 2

Rodar o efeito uma vez após a montagem.

Resposta da atividade 3

Carregando, sucesso e erro.

O arquivo completo

Referência do exemplo 05-react-efeitos, reproduzida aqui para que você possa conferir sem sair da página.

styles.css

:root{--ink:#1a1a1a;--bg:#f7f4ef;--brand:#1f3a5f;--accent:#c45c26;--line:#d9d2c5;--focus:#0b57d0}
*{box-sizing:border-box}html{font-family:"Segoe UI",Tahoma,sans-serif;color:var(--ink);background:var(--bg)}
body{margin:0;line-height:1.5}a:focus-visible,button:focus-visible,input:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.skip{position:absolute;left:-999px}.skip:focus{left:1rem;top:1rem;z-index:10;background:#fff;padding:.5rem}
header,footer{background:var(--brand);color:#fff;padding:1rem 1.25rem}header a,footer a{color:#fff}
main{max-width:52rem;margin:0 auto;padding:1.25rem}h1{color:var(--brand);margin-top:0}
.card{background:#fff;border:1px solid var(--line);padding:1rem;margin:.75rem 0}
button{background:var(--accent);color:#fff;border:0;padding:.55rem 1rem;cursor:pointer}
.board{display:grid;grid-template-columns:repeat(3,4.5rem);gap:.4rem}
.square{width:4.5rem;height:4.5rem;font-size:1.5rem;background:#fff;border:2px solid var(--brand)}
label{display:block;margin:.5rem 0 .2rem;font-weight:600}
input,textarea{width:100%;max-width:28rem;padding:.45rem;border:1px solid var(--line)}
ul.nav{list-style:none;padding:0;display:flex;gap:1rem;flex-wrap:wrap;margin:0}
.status{font-weight:600;margin:.75rem 0}