Recebendo Dados
Os dados ainda estão fixos. Queremos obter a lista de anotações de algum servidor. Ainda bem que já implementamos o servidor REST na aula anterior! Agora só precisamos implementar o cliente. Para isso, vamos utilizar o axios. Comece instalando o axios no nosso projeto. No terminal, dentro da pasta do projeto (notes-frontend), rode o comando a seguir: npm i axios
Agora modifique o seu código do src/App.js
para utilizar o axios para realizar uma requisição GET para o servidor REST desenvolvido na última aula:
import axios from "axios";
import Note from "./components/Note";
import "./App.css";
function App() {
const notes = [
{
id: 1,
title: "Receita de miojo",
content:
"Bata com um martelo antes de abrir o pacote. Misture o tempero, coloque em uma vasilha e aproveite seu snack :)",
},
{
id: 2,
title: "Sorvete de banana",
content: "Coloque a banana no congelador e espere.",
},
];
axios
.get("http://localhost:8000/notes/")
.then((res) => console.log(res));
return (
<>
{notes.map((note) => (
<Note key={`note__${note.id}`} title={note.title}>
{note.content}
</Note>
))}
</>
);
}
export default App;
Importante!
Antes de testar, lembre-se de colocar o servidor da aula passada para rodar.
Importante!
Ao tentar executar o código acima, o seguinte erro deve aparecer no console do navegador:
Esse erro ocorre porque o navegador está tentando te proteger. Ele não fará requisições para servidores que não aceitam explicitamente requisições de outros endereços. O nosso frontend está rodando em localhost:3000
e o backend em localhost:8000
. Eles são endereços diferentes, então a requisição é bloqueada.
Para esse tipo de requisição ser bloqueada, precisamos adicionar o header CORS, indicando que aceitamos essa requisição:
No projeto Django, adicione o módulo django-cors-headers
:
Adicione o app no INSTALLED_APPS
no arquivo getit/settings.py
:
Adicione também o MIDDLEWARE
como o primeiro elemento da lista, no mesmo arquivo:
Finalmente, no final do mesmo arquivo de configuração, adicione:
Depois de realizar as adaptações no servidor, seu código deve funcionar e a requisição devolve a lista de anotações do servidor.
Guardando os dados
O app já é capaz de fazer a requisição e receber os dados, mas ainda não mostra nada na tela. Poderíamos simplesmente guardar os dados em uma variável e utilizá-la para renderizar os componentes. Pensamos em algo assim:
import axios from "axios";
import Note from "./components/Note";
import "./App.css";
function App() {
const notes = axios.get("http://localhost:8000/notes/").then((res) => setNotes(res.data));
return (
<>
{notes.map((note) => (
<Note key={`note__${note.id}`} title={note.title}>
{note.content}
</Note>
))}
</>
);
}
export default App;
Erro
O código acima não funciona. Como a função
axios.get
é assíncrona, a variável notes
não é preenchida com os dados da requisição.
O problema é que a requisição é feita em uma chamada assíncrona, assim, não sabemos quando o resultado será obtido. Como o componente é uma função, ele não pode armazenar estado como um objeto. Ela é executada para gerar a tela e termina a execução.
Por isso foram criados os chamados hooks, que permitem o armazenamento de estado em componentes funcionais. Vamos utilizar o useState
para armazenar estado. Modifique o arquivo src/App.jsx
:
import axios from "axios";
import { useState } from "react";
import Note from "./components/Note";
import "./App.css";
function App() {
const [notes, setNotes] = useState([]); // Remova o array de notes que existia na versão anterior
axios.get("http://localhost:8000/notes/").then((res) => setNotes(res.data));
console.log(notes);
return (
<>
{notes.map((note) => (
<Note key={`note__${note.id}`} title={note.title}>
{note.content}
</Note>
))}
</>
);
}
export default App;
O useState
devolve o valor do estado atual e uma função que permite modificar o estado. Ele também recebe o valor inicial do estado, no caso um array vazio.
Ao executar o código acima, o console do navegador deve mostrar o JSON de anotações diversas vezes (recomendo que você feche a aba até implementar o resto do código).

O que acontece é que toda vez que o estado muda, o componente é renderizado novamente, ou seja, a função é re-executada. Assim, quando a requisição é finalizada, os dados são utilizados para atualizar a variável notes
do estado. Quando isso ocorre, o componente é renderizado novamente. Isso faz com que uma nova requisição ocorra, que por sua vez realizará outra atualização do estado, que fará com que uma nova requisição ocorra, que por sua vez... enfim, você acabou de implementar a versão de componentes React de um loop infinito!

Queremos realizar a requisição apenas uma vez. Para isso, existe um outro hook chamado useEffect
, que permite definir algumas condições para quando ele deve ser re-executado. Modifique novamente o arquivo src/App.js
:
import axios from "axios";
import { useEffect, useState } from "react";
import Note from "./components/Note";
import "./App.css";
function App() {
const [notes, setNotes] = useState([]);
useEffect(() => {
axios
.get("http://localhost:8000/notes/")
.then((res) => setNotes(res.data));
}, []);
console.log(notes);
return (
<>
{notes.map((note) => (
<Note key={`note__${note.id}`} title={note.title}>
{note.content}
</Note>
))}
</>
);
}
export default App;
O primeiro argumento do useEffect
é uma função. Essa função será executada quando o conteúdo do segundo argumento (um array) mudar. Como o array está vazio, a função será executada apenas uma vez.
Carregando imagens e outros arquivos estáticos
Para continuar, avance para a próxima seção: