Olá pessoal! Chegamos a última parte do nosso tutorial Pokedex com React! Nesta última parte, gerenciaremos o estado e buscaremos dados da poke api. Por fim, usaremos os dados do Pokemón para preenchimento do nosso DetailView. Para dar sequência, você precisará dos artigos anteriores:
- Parte 1: https://www.mundojs.com.br/2020/03/18/criando-pokedex-com-react-parte-1/
- Parte 2: https://www.mundojs.com.br/2020/04/02/criando-pokedex-com-react-parte-2/
- Parte 3: https://www.mundojs.com.br/2020/04/03/criando-pokedex-com-react-parte-3/
- Parte 4: https://www.mundojs.com.br/2020/04/03/criando-pokedex-com-react-parte-4/
Passing Events:
Precisamos criar um evento de clique para cada um dos nossos PokeCells, afim de buscar os dados Pokemón da Poke API. Para fazer isso, criaremos a função como parte da classe APP e depois transmitiremos como props para cada um de nossos PokeCells.
Abra o arquivo App.js e cria uma função chamada handleOnClick, com o parâmetro id. No corpo da função, inclua um console.log do argumento id.
import React, { Component } from 'react'; import PokeList from './PokeList'; import DetailView from './DetailView'; import './styles/App.css'; class App extends Component { constructor() { super(); this.state = {}; } handleOnClick(id){ console.log(id); } render() { return ( <div className = "App"> <PokeList /> <DetailView /> </div> ); } }
Precisamos passar esta função através do componente PokeList. Adicione a função handleOnClick para o PokeList:
render() { return ( <div className = "App"> <PokeList handleOnClick = {this.handleOnClick} /> <DetailView /> </div> ); }
Usamos a palavra-chave this, porque handleOnClick é um método da classe App. No entanto, se não utilizarmos o bind, perderemos o contexto disso quando usarmos essa função no componente PokeList. Então, vamos vincular handleOnClick à classe atual:
class App extends Component { constructor() { super(); this.state = {}; this.handleOnClick = this.handleOnClick.bind(this); }
Agora, abra o seu arquivo PokeList.js e siga esta etapa:
- Desconstrua o handleOnCLick a partir dos argumentos PokeList;
- Adicione o método handleOnClick como um prop de PokeCells:
const PokeList = ({handleOnClick}) => { const cells = pokeClasses.map(pokeClass => { return ( <PokeCell key = {pokeClass.id} pokeClass = {pokeClass} handleOnClick = {handleOnClick} /> ); }); return ( <section className="poke-list"> {cells} </section> ) }
Abra seu arquivo PokeCell e siga os seguintes passos:
- Desconstrua o handleOnClick a partir dos argumentos PokeCell;
- Adicione um evento onClick dentro da guia do botão e atribua a ele uma função anônima que chama handleOnClick com a variável id como parâmetro;
Agora, sempre que clicarmos no botão PokeCell, o ID do Pokémon clicado será registrado no console:
import React from 'react'; import sprites from '../assets/sprites.png'; import './styles/PokeCell.css'; const PokeCell = ({ pokeClass, handleOnClick }) => { const { id, backgroundPosition } = pokeClass; const style = { backgroundImage: `url(${sprites})`, backgroundPosition}; return <button onClick={() => handleOnClick(id)} style={style} className="poke-cell"></button> }; export default PokeCell;
Pokemon Helper:
Vamos criar uma classe Pokemon para limpar os dados da API que vamos buscar. Dessa forma, podemos gerenciar os dados de Pokemon mais facilmente. Dentro do diretório src, crie um arquivo Pokemon.js. Dentro deste arquivo Pokemon.js, adicione o código:
class Pokemon { constructor(data) { this.id = data.id; this.name = data.name; this.sprite = data.sprites.front_default; this.type = data.types[0].type.name; } } export default Pokemon;
Agora, quando buscarmos os dados, instanciaremos um novo objeto Pokemon e passa-lo aos dados buscados.
Buscando os dados:
Abra o arquivo App.js e siga estas etapas:
- Importe a classe Pokemon na parte superior do arquivo;
- No método handleOnClick, faça um fetch para a API. Adicione uma rota de URL dinâmico com o argumento id;
- Resolve a promise e crie uma nova instância de Pokecom com os dados buscados;
- Adicione um console.log do objeto Pokemon para ver os dados do Pokemon quando um PokeCell é clicado.
handleOnClick(id){ fetch(`http://pokeapi.co/api/v2/pokemon/${id}/`) .then(res=> res.json()) .then(data => { const pokemon = new Pokemon(data); console.log(pokemon); }) .catch (err => console.log(err)); }
State:
Agora que nós já realizamos o fetch dos dados dos Pokemon, precisamos passar esses dados para o DetailView para mostrá-los.
Para fazer isso, precisamos tirar o objeto Pokemon da promise resolvida e armazená-lo no estado de nosso aplicativo. Na função construtora do componente App, adicione uma nova chave ao objeto de estado com o valor de um objeto vazio.
constructor() { super(); this.state = { pokemon: {} }; this.handleOnClick = this.handleOnClick.bind(this); }
Para atualizar o estado do pokemon, o React nos fornece uma função chamada setState. Essa função usa um objeto como argumento, onde precisamos especificar a chave que queremos atualizar e atribuir um novo valor a ele. Toda vez que essa função é chamada, o React renderiza novamente todos os componentes filhos.
handleOnClick(id){ fetch(`http://pokeapi.co/api/v2/pokemon/${id}/`) .then(res=> res.json()) .then(data => { const pokemon = new Pokemon(data); this.setState({pokemon}); }) .catch (err => console.log(err)); }
Agora que armazenamos nossos dados de Pokemon no estado do aplicativo, podemos acessá-los na função de renderização. Passe o estado pokemon para o componente DetailView como um suporte. Como a propriedade state faz parte da classe App, precisamos incluir a palavra-chave this para acessá-la:
render() { return ( <div className = "App"> <PokeList handleOnClick = {this.handleOnClick} /> <DetailView pokemon = {this.state.pokemon} /> </div> ); }
Exibindo os dados:
Abra o arquivo DetailView.js e siga estas etapas:
- Desconstrua o pokemon a partir dos argumentos DetailView;
- Desconstrua o ID, nome, Sprite e tipo da variável pokemon;
- Na tag da imagem, adiciona um atributo src e atribua a variável Sprite envolvida em chaves;
- Entre as tags h1, adicione as variáveis id e name envoltas em chaves;
- Na tag p, adicione a variável type envolvida em chaves.
import React from 'react'; import './styles/DetailView.css'; const DetailView = ({pokemon}) => { const { id, name, sprite, type } = pokemon; return ( <section className="detail-view"> <img src={sprite} className='sprite-image' alt='sprite' /> <div className='data-wrapper'> <h1 className='data-name'>ID: {name}</h1> <p className="data-char">Type: {type}</p> </div> </section> ) } export default DetailView;
E com isso, terminamos a nossa PokeDex! Gostou desta sequência de artigos? Comente abaixo!
Referências: https://blog.cloudboost.io/lets-build-a-pokedex-with-react-part-5-b61d730de5fc