Como consumir dados de API externa utilizando React e Axios

Como consumir dados de API externa utilizando React e Axios

Emanuelly Leoncio. Fala, dev! Tudo certo? Para quem desenvolve aplicações, pode ocorrer a necessidade de consumir uma API externa. Neste artigo, iremos criar uma página em React que irá consumir a API chamada HP-API, a qual traz diversas informações dos personagens do filme Harry Potter, suas casas e feitiços.

Nosso projeto irá conter cards com o nome e foto de alguns alunos de Hogwarts. Também iremos implementar um modal, que irá exibir mais dados do aluno selecionado, como ano de nascimento, casa e patrono. Para conectar nosso projeto com a API, usaremos a biblioteca axios.

Nosso resultado final será o seguinte:


Mãos à obra!

Configurações iniciais do projeto

Vamos iniciar o projeto. Crie uma pasta onde ele será armazenado. Aqui iremos nomear como react-api. Em seu terminal, rode o seguinte código:

npx create-react-app react-api


Em seguida:

cd react-api

npm start


Uma nova janela irá se abrir em seu navegador, como mostrado na figura abaixo.


Agora iremos fazer a organização das nossas pastas e arquivos. Neste ponto, você deve estar com a seguinte estrutura de pastas:



Podemos deletar os seguintes arquivos:

Na pasta public:

  • logo192.png e logo512.png;
  • manifest.json;
  • robots.txt.
  • Na pasta src iremos apagar todos exceto o index.js e o App.css;

Mais alguns ajustes precisam ser feitos:

  • Na pasta public, em index.html: retire os comentários e referências das imagens que apagamos. Você também pode adicionar um título na tag <title>. Aqui, colocamos Hogwarts.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="theme-color" content="#000000" />
  <meta
    name="description"
    content="Web site created using create-react-app"
  />
  <title>Hogwarts</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>


Na pasta src:

  • Crie uma nova pasta chamada page e mova o App.css para dentro dela;
  • Renomeie o App.css para style.css. Apague todo o código existente nele e adicione:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}


Na pasta page, adicione um novo arquivo index.js com o seguinte trecho:

import "./style.css";

export default function Main() {

return (
  <div>
      <h1>Olá!</h1>
  </div>
);
};


No arquivo index.js, que agora está na raiz, deixe somente o seguinte código:

import React from 'react';
import ReactDOM from 'react-dom/client';
import Main from './page/index';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
  <Main />
</React.StrictMode>
);



Com isso, não teremos mais nenhum erro no terminal:


Suas pastas e arquivos estão com esta estrutura agora:


E sua página estará com esta cara inicial:


Ajustando a Main

Iniciamos o ajuste da página Main adicionando as fontes do nosso projeto. Aqui usaremos Montserrat e MedievalSharp. Você pode escolher essas ou outras fontes utilizando o Google Fonts. O link da formatação foi adicionado em index.html.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=MedievalSharp&family=Montserrat:wght@500;600;700&display=swap" rel="stylesheet">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="theme-color" content="#000000" />
  <meta
    name="description"
    content="Web site created using create-react-app"
  />
  <title>Hogwarts</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>


Agora, vamos adicionar algumas informações para visualizar melhor a estilização. Em index.js, colocaremos o título principal da nossa página, e um container de informações.

import "./style.css";

export default function Main() {
return (
  <div className="container-main">
      <div className="container-main-title">
        <h1>Hogwarts Students</h1>
      </div>

    <div className="container-main-info">
      <span>Nome: Hermione</span>
      <span>Idade: 14 anos</span>
      <span>Casa: Grifinória</span>
    </div>
  </div>
);
};


Em style.css, vamos configurar o background da página, font-family e font-size de cada div.

* {
padding: 0;
margin: 0;
box-sizing: border-box;
}

.container-main {
height: 100vh;
width: 100vw;
background: rgb(2,0,36);
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(11,11,148,1) 35%, rgba(132,0,255,1) 100%);
}

.container-main-title h1 {
color: #efefef;
font-family: MedievalSharp;
font-weight: 500;
font-size: 70px;
text-align: center;
margin-bottom: 10px;
}

.container-main-info {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #efefef;
font-family: Montserrat;
font-weight: 400;
font-size: 20px;
}


Ao final, teremos o seguinte:


Adicionando ícones

Crie uma pasta chamada assets dentro de src. Nela iremos adicionar as imagens do brasão de cada uma das quatro casas de Hogwarts e também um ícone “X” para fechar o modal que vamos construir. Você pode encontrar imagens como essas facilmente na web. Escolha os de sua preferência e salve na pasta.

A estrutura das pasta ficou assim:


Configurando o axios

Para adicionar a biblioteca axios, rode no terminal de seu projeto:

npm install axios


Dentro de src, crie uma pasta chamada services, e dentro dela, adicione um arquivo chamado api.js. Neste novo arquivo, coloque o seguinte trecho de configuração da api.

import axios from 'axios';

export default axios.create({
  baseURL: 'https://hp-api.onrender.com',
  timeout: 10000,
  headers: { 'Content-Type': 'application/json' }
});


Construindo os componentes

Para deixar o projeto mais organizado, vamos construir dois componentes: o Person, por onde será passado as informações de cada aluno da escola Hogwarts vindos da API; e o Modal.

Crie uma pasta chamada components, e dentro dela mais duas pastas: Person e Modal. Dentro de cada uma, adicione um arquivo index.js e um style.css. Ficará assim:



Componente Person

Vamos construir o componente Person, que irá receber informações do arquivo Main por meio da prop item.

Em index.js, adicione:

import "./style.css";

export default function Person({item}) {
  return (
  <div className="container-person">
    <div className="container-person-img">
      <img src={item.image} alt="Profile"></img>
    </div>
    <div className="container-person-info">
      <h3>{item.name}</h3>
    </div>
  </div>
);
};


Em style.css, adicione:

.container-person {
background-color: rgba(239, 239, 239, 0.342);
border-radius: 3px;
width: 150px;
height: 200px;
display: flex;
align-items: center;
justify-content: space-evenly;
flex-direction: column;
cursor: pointer;
}

.container-person:hover{
transform: scale(1.1);
}

.container-person-info {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
font-family: Montserrat;
}

.container-person-info h3 {
font-size: 12px;
font-weight: bold;
}

.container-person-img img{
width: 100px;
height: 110px;
border-radius: 2px;
}



No arquivo Main, vamos trabalhar com dois hooks: useState e useEffect. O useState irá criar e gerenciar o estado das informações vindas da API que queremos manipular, que serão os estudantes e suas casas, e também a ação de abrir/fechar modal e populá-lo com dados do estudante selecionado. Já o useEffect será responsável por executar a função async/await assim que o componente for renderizado.

Será na Main que iremos adicionar nossa função async/await, que irá resgatar as informações da API. Utilizaremos a rota "/api/characters/students", a qual retornará um array de objetos. Cada objeto contém dados diversos de um aluno, e iremos popular nosso modal com as chaves name, house, dateOfBirthday e patronus.

Abaixo segue imagem do objeto obtido da API e as chaves destacadas que serão utilizadas.


Para darmos seguimento no consumo da api externa, inclua o código abaixo no arquivo Main:

import { useEffect, useState } from "react";


export default function Main() {

const [students, setStudents] = useState([]);


async function loadPeople() {

try {

const response = await api.get("/api/characters/students");

const main = response.data.splice(10);

setStudents(response.data);

} catch (error) {

console.log(error);

}

};


useEffect(() => {

loadPeople();

}, []);


return (

<div className="container-main">

<div className="container-main-title">

<h1>Hogwarts Students</h1>

</div>

<div className="container-main-info">

{students.map((item) => (

<Person

key={item.id}

item={item}

/>

))}

</div>

</div>

);

}

Nossa página ficou da seguinte forma:


Observe que os cards dos estudantes ficaram centralizados, porém estão formando uma coluna única. Para ajustar isso e deixá-los enfileirados na horizontal, precisamos ajustar nosso css do arquivo Main:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.container-main {
  height: 100vh;
  width: 100vw;
  background: rgb(2,0,36);
  background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(11,11,148,1) 35%, rgba(132,0,255,1) 100%);

  position: relative;
}


.container-main-title h1 {
    color: #efefef;
    font-family: MedievalSharp;
    font-weight: 500;
    font-size: 60px;
    text-align: center;
    margin-bottom: 10px;
}

.container-main-info {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 150px;
    color: #efefef;
    font-family: Montserrat;
    font-weight: 400;
    font-size: 20px;

    margin-top: 30px;
}


Com isso, temos:


Componente Modal

Dentro da pasta services, crie um arquivo chamado data.js. Nele, vamos adicionar um array de objetos contendo id, nome da casa e sua respectiva imagem (anteriormente adicionada na pasta assets), os quais iremos utilizar em nosso Modal.

import gryffindor from '../assets/gryffindor-icon.png';
import hufflepuff from '../assets/hufflepuff-icon.png';
import ravenclaw from '../assets/ravenclaw-icon.png';
import slytherin from '../assets/slytherin-icon.png';

const houses = [
  {
    id: 1,
    image: gryffindor,
    name: 'Gryffindor',
  },
  {
    id: 2,
    image: hufflepuff,
    name: 'Hufflepuff',
  },
  {
    id: 3,
    image: ravenclaw,
    name: 'Ravenclaw',
  },
  {
    id: 4,
    image: slytherin,
    name: 'Slytherin',
  }
];

export default houses;


Precisamos criar os estados que irão manipular as informações para o aluno que desejamos abrir o modal.

Para isso, vamos adicionar os estados:

  • ShowModal: que será responsável por abrir e fechar o modal;
  • CurrentPerson: que irá observar qual aluno está sendo selecionado;
  • House: que irá buscar em data.js as informações da casa do aluno selecionado.

Vamos também adicionar algumas funções:

  • HandlePicture: que irá comparar as informações trazidas da API para o aluno selecionado e buscar a imagem correta da casa em data.js;
  • HandleSelectPerson: irá setar em nosso modal as informações corretas do aluno selecionado;
  • HandleClose: responsável por fechar o modal, quando clicarmos no ícone “X”.

Portanto, temos:


O código:

import "./style.css";
import Person from "../components/Person";
import Modal from "../components/Modal";
import api from "../services/api";
import houses from '../services/data';
import { useEffect, useState } from "react";

export default function Main() {
  const [students, setStudents] = useState([]);
  const [showModal, setShowModal] = useState(false);
  const [currentPerson, setCurrentPerson] = useState([]);
  const [house, setHouse] = useState('');

  function handlePicture(item) {
    let picture = houses.find((house) => {
      return house.name === item.house
    });
    setHouse(picture.image);
  }

  function handleSelectPerson(item) {
    setShowModal(true);
    setCurrentPerson(item);
    handlePicture(item)
  };

  function handleClose() {
    setShowModal(false);
  }

  async function loadPeople() {
    try {
      const response = await api.get("/api/characters/students");
      const main = response.data.splice(10);
      setStudents(response.data);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    loadPeople();
  }, []);

  return (
    <div className="container-main">
      <div className="container-main-title">
        <h1>Hogwarts Students</h1>
      </div>
      <div className="container-main-info">
        {students.map((item) => (
          <Person
            key={item.id}
            item={item}
            handleSelectPerson={handleSelectPerson}
          />
        ))}
      </div>
      <Modal
        show={showModal}
        handleClose={handleClose}
        currentPerson={currentPerson}
        houseImage={house}
      />
    </div>
  );
};


Observe que já adicionamos nosso componente Modal, e passamos como props o showModal, handleClose, currentPerson e houseImage, para serem manipulados no componente.


Por fim, vamos adicionar os códigos finais para nosso componente Modal.

Em index.js:

import './style.css';
import btnClose from '../../assets/btn-close.svg';

export default function Modal({show, handleClose, currentPerson, houseImage}) {

  return (
    <>
      {show &&
        <div className="modal">
          <div className="container-modal">
            <div className="container-modal-infos">
              <img
                src={btnClose}
                alt="Botão fechar"
                className="btn-close"
                onClick={() => handleClose(true)}></img>
              <div>
                <img
                  className="container-modal-img"
                  src={currentPerson.image}
                  alt="Profile"></img>
              </div>
              <div className="container-modal-info">
                <div className='info-detail'>               
                  <span><strong>Name:</strong> {currentPerson.name}</span>
                  <span><strong>Patronus:</strong> {currentPerson.patronus}</span>
                  <span><strong>Birthday:</strong> {currentPerson.dateOfBirth}</span>
                  <span><strong>House:</strong> {currentPerson.house}</span>
                </div>
                <img src={houseImage} alt="House"></img>
              </div>
            </div>
          </div>
        </div>
      }
    </>
  );
};


Em style.css:

.modal{
  display: flex;
  justify-content: center;
  align-items: center;

  position: absolute;
}

.container-modal {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(121, 120, 120, 0.8);
  font-family: Montserrat;

  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.container-modal-img {
  width: 160px;
  height: 220px;
  border-radius: 1px;
}

.btn-close {
  width: 16px;
  height: 16px;

  position: absolute;
  top: 360px;
  right: 730px;
  cursor: pointer;
}

.container-modal-infos {
  display: flex;
  align-items: center;
  gap: 20px;
  padding-left: 20px;
  padding-right: 10px;
  border-radius: 2px;
  background-color: rgb(207, 205, 205);
  width: 420px;
  height: 300px;
}

.container-modal-info {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container-modal-info img {
width: 48px;
height: 48px;
margin-top: 20px;
}

.info-detail {
  display: flex;
  flex-direction: column;
  gap: 10px;
}


Assim, concluímos nossa página:

Conclusão

Neste tutorial, vimos como consumir uma API externa em um projeto React, utilizando a biblioteca axios. Diversas API’s públicas podem ser encontradas na web, com as mais diferentes temáticas. Segue aqui um repositório do GitHub com uma listagem bem diversificada. Agora é só colocar a criatividade em prática!

💡
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.