O que vamos construir?
Nós vamos estender nossa demo do mapa original com algumas estatísticas básicas que podemos recuperar do API NovelCOVID. Para ter uma ideia, aqui está minha demo Estou baseando isso.
Enquanto você não é obrigado a ter concluído Parte 1 para aplicar esses conceitos, ele definitivamente ajuda e permite que você configure um mapa para o seu painel. Se você gostaria de começar por aí, o que eu recomendo, confira Como criar um aplicativo de painel e mapa de Coronavírus (COVID-19) com Gatsby e Leaflet primeiro.
Woah, um aplicativo de mapeamento?
Sim. Se você nunca jogou com mapas antes, não desanime! Não é tão ruim quanto você provavelmente pensa. Se você preferir começar com o básico do mapeamento, pode leia mais sobre como o mapeamento funciona primeiro.
Do que precisamos antes de começar?
Para esta explicação, você precisa de um aplicativo React de alguma forma. Trabalharei com o painel que criamos anteriormente em minha última explicação passo a passo, que inclui um mapa dos casos de coronavírus (COVID-19) por país.
Eu recomendo começar com o tutorial anterior, mas se você quiser pular o mapa e começar de novo, a maneira mais fácil provavelmente seria usar Criar aplicativo React, Gatsbyou Next.js.
Etapa 1: atualize como buscamos nossos dados e as estatísticas
Para começar nosso painel de estatísticas, faremos um pequeno trabalho de preparação, alterando a maneira como estamos buscando os dados. O objetivo aqui é agrupar nossa lógica de solicitação de forma reutilizável, para que possamos usá-la para os dados de nossos países e nossos novos dados estatísticos.
Criando um novo gancho React para buscar dados
Mergulhando, o primeiro a fazer é criar um novo Gancho de reação que servirá como buscamos os dados. Para começar, crie um novo arquivo no diretório hooks chamado useTracker.js
e adicione uma linha dentro de hooks/index.js
exportá-lo:
// New file src/hooks/useTracker.js// This will be empty for now
// Inside hooks/index.jsexport { default as useTracker } from './useTracker';
Dentro do nosso useTracker.js
arquivo, vamos configurar nossa lógica de solicitação. Como é um arquivo longo, copie e cole a coisa toda antes de analisarmos o que ela faz:
import { useEffect, useState } from 'react';import axios from 'axios';const API_HOST = 'https://corona.lmao.ninja/v2';const ENDPOINTS = [ { id: 'all', path: '/all', isDefault: true }, { id: 'countries', path: '/countries' }]const defaultState = { data: null, state: 'ready'}const useTracker = ({ api = 'all' }) => { const [tracker = {}, updateTracker] = useState(defaultState) async function fetchTracker() { let route = ENDPOINTS.find(({ id } = {}) => id === api); if ( !route ) { route = ENDPOINTS.find(({ isDefault } = {}) => !!isDefault); } let response; try { updateTracker((prev) => { return { ...prev, state: 'loading' } }); response = await axios.get(`${API_HOST}${route.path}`); } catch(e) { updateTracker((prev) => { return { ...prev, state: 'error', error: e } }); return; } const { data } = response; updateTracker((prev) => { return { ...prev, state: 'ready', data } }); } useEffect(() => { fetchTracker() }, [api]) return { fetchTracker, ...tracker }};export default useTracker;
Começando do topo:
- Importamos nossas dependências: vamos usar o Reacts
useEffect
euseState
ganchos para gerenciar nossos pedidos - Definimos constantes padrão: temos um ponto de extremidade da API base para nossos dados, uma lista dos pontos de extremidade disponíveis que usaremos e um objeto de estado que armazenará nossos dados
- Nós definimos nossa
useTracker
hook: nosso hook inclui um argumentoapi
que nos permitirá especificar qual terminal usaremos para fazer nossa solicitação - Configuramos uma instância de estado: queremos acompanhar nossos dados buscados e, por isso, criamos um
tracker
instância estadual que poderemos atualizar - Criamos uma assíncrona
fetchTracker
função: usaremos isso para fazer nossa solicitação real - Dentro de nossa função: primeiro encontramos a rota da API e criamos nossa URL, atualizamos nossa instância de estado para um estado “loading”, tentamos fazer nossa solicitação, detectamos erros se houver algum e, finalmente, se a solicitação for bem-sucedida, atualizamos nosso estado com esses dados
- Ativamos nossa função: usar um
useEffect
gancho, acionamos nossafetchTracker
função para fazer a solicitação. Temos apenas uma dependência deapi
. Isso significa que a função será acionada apenas na primeira vez e sempre que oapi
valor que passamos em mudanças. Não alteraremos esse valor, mas pode ser útil em outros casos, se você alterar dinamicamente a API usada - Retornamos nosso rastreador: o objeto retornado inclui nossos
tracker
dados, bem como a nossafetchTracker
função que poderíamos usar para buscar novamente os dados, se desejarmos
E com tudo isso, temos um novo gancho que buscará dados da API NovelCOVID.
Usando nosso novo gancho rastreador
Para usar esse gancho, vamos pular para src/pages/index.js
remova nossa axios
importe se estiver lá e importe nosso gancho:
import { useTracker } from 'hooks';
Com nosso gancho, vamos substituir nossa solicitação de dados do país original. Primeiro, adicione o seguinte na parte superior do IndexPage
componente:
const { data: countries = [] } = useTracker({ api: 'countries'});const hasCountries = Array.isArray(countries) && countries.length > 0;
Isso nos permitirá buscar os dados de nosso país e saber se temos algum resultado. Em seguida, vamos substituir nossa solicitação original.
Dentro do nosso mapEffect
função, vamos remover o axios
solicitação, além da resposta, o objeto de dados desestruturado e o hasData
constante.
Em seguida, substitua hasData
com hasCountries
:
if ( !hasCountries ) return;
E substitua data
com countries
no geoJson
objeto onde mapeamos nossos recursos:
features: countries.map((country = {}) => {
Nesse ponto, se você clicar em salvar e atualizar, não deverá notar nenhuma diferença em relação ao que possuía anteriormente.
Adicione um pedido para nossas estatísticas
Agora que estamos usando nosso useTracker
para buscar os dados de nosso país, vamos usar isso também para buscar nossas estatísticas.
Bem ao lado de onde montamos nossa useTracker
antes, vamos adicionar outra solicitação:
const { data: stats = {} } = useTracker({ api: 'all'});
E se adicionarmos um console.log
declaração abaixo para ver o que está dentro stats
:
console.log('stats', stats);
Deveríamos ver nossa stats
objeto de dados desconectado!
Etapa 2: adicionando estatísticas ao nosso painel
Agora que temos nossos dados disponíveis para uso, vamos usá-lo!
Para começar a adicionar nossas estatísticas ao painel, vamos criar uma estrutura de dados que nos permita configurar facilmente os dados que queremos usar.
Para fazer isso, primeiro vamos criar uma nova matriz chamada dashboardStats
abaixo hasCountries
na parte superior do componente da página:
const dashboardStats = [];
Dentro dessa matriz, vamos adicionar alguns novos objetos que especificam nossos dados que estamos retirando do stats
objeto que solicitamos. Para começar, vamos tentar adicionar:
const dashboardStats = [ { primary: { label: 'Total Cases', value: stats?.cases }, secondary: { label: 'Per 1 Million', value: stats?.casesPerOneMillion } }, { primary: { label: 'Total Deaths', value: stats?.deaths }, secondary: { label: 'Per 1 Million', value: stats?.deathsPerOneMillion } }, { primary: { label: 'Total Tests', value: stats?.tests }, secondary: { label: 'Per 1 Million', value: stats?.testsPerOneMillion } }]
A razão pela qual estamos dividindo isso em primary
e secondary
chaves, vamos usar isso para diferenciar entre estatísticas logicamente semelhantes que queremos estilizar um pouco diferente.
Nota: se você não estiver familiarizado com o ?.
sintaxe, é chamado Encadeamento opcional. Isso nos permite encadear nossas propriedades sem se preocupar se os objetos existem. E se stats
é indefinido, ele simplesmente retornará indefinido em vez de gerar um erro.
Com nossos dados estatísticos, vamos adicionar o rastreador ao nosso mapa. Vamos remover nossa atual e inclua-o aninhado dentro da nossa div tracker da seguinte maneira:
{ dashboardStats.map(({ primary = {}, secondary = {} }, i) => { return ( - { primary.value && (
{ primary.value } { primary.label }
)} { secondary.value && ( { secondary.value } { secondary.label }
)} ); })}
Este código deve seguir imediatamente o
componente se você estiver acompanhando.
Para explicar o que estamos fazendo:
- Estamos criando um div “rastreador” que organizará nossas estatísticas
- Nós mudamos nossa
- Criamos uma seção separada chamada "tracker-stats"
- Dentro disso, criamos uma lista não ordenada (
ul
) - Dentro da nossa lista, percorremos todas as nossas estatísticas dentro
dashboardStats
- Para cada estatística, criamos um novo elemento de lista (
li
) e inclui 2 parágrafos opcionais que incluem nossos dados estatísticos primários e dados estatísticos secundários
Depois que recarregarmos nossa página, veremos agora algumas estatísticas:
Agora que temos nossas estatísticas em nossa página, vamos fazer com que pareçam estar em um painel.
Vamos criar um novo arquivo chamado _tracker.scss
dentro do nosso src/assets/stylesheets/components
diretório. Depois que esse arquivo for criado, adicione-o adicionalmente ao src/assets/stylesheets/components/__components.scss
Arquivo:
@import "tracker";
Com nosso novo arquivo de estilo de componente pronto, vamos adicionar alguns estilos ao _tracker.scss
:
.tracker-stats { color: white; background-color: $blue-grey-900; border-top: solid 1px darken($blue-grey-900, 5); ul { display: grid; grid-template-columns: 1fr 1fr 1fr; list-style: none; padding: 0; margin: 0; }}.tracker-stat { font-size: 2em; text-align: center; padding: .5em; border-right: solid 1px darken($blue-grey-900, 5); border-bottom: solid 1px darken($blue-grey-900, 5); strong { font-weight: normal; color: $blue-grey-300; }}.tracker-stat-primary { margin: 0; strong { display: block; font-size: .5em; }}.tracker-stat-secondary { font-size: .5em; margin: .8em 0 0; strong { font-size: .8em; margin-left: .4em; }}
Acima - estamos adicionando cores e efeitos organizacionais, como usar Grade CSS, para permitir que nossos dados sejam organizados de maneira fácil de ler e com boa aparência! Também estamos usando algumas variáveis de cores pré-existentes que são usadas no projeto para manter o uso de cores consistente.
Depois de salvar esses estilos e recarregar a página, ela ficará muito melhor:
A partir daqui, fique à vontade para adicionar mais estatísticas ou ajustá-las ao seu gosto. Na demonstração que criei, adicionei as estatísticas de casos ativos, casos críticos e casos recuperados. Se você quiser fazer o mesmo, pode confira o commit.
Etapa 3: tornar os dados amigáveis ao ser humano
Agora, o restante deste passo a passo pode ser considerado opcional, mas, em última análise, queremos que as pessoas possam ler essas estatísticas, certo? Então, vamos tornar os números um pouco mais fáceis de ler.
Primeiro, vamos abrir nossa src/lib/util.js
arquivo e adicione esta função:
/** * commafy * @description Applies appropriate commas to large numbers */export function commafy(value) { let numberString = `${value}`; numberString = numberString.split(''); numberString.reverse(); numberString = numberString.reduce((prev, current, index) => { const shouldComma = (index + 1) % 3 === 0 && index + 1 < numberString.length; let updatedValue = `${prev}${current}`; if ( shouldComma ) { updatedValue = `${updatedValue},`; } return updatedValue; }, ''); numberString = numberString.split(''); numberString.reverse() numberString = numberString.join(''); return numberString;}
Essa função pega um número e o transforma em uma string com vírgulas. Para percorrer o que faz:
- Recebe um valor como argumento. Para nosso uso, esse valor provavelmente será um número.
- Ele converte o valor em uma string. Usaremos isso para trabalhar com a adição de vírgulas ao nosso número.
- Dividimos essa string em uma matriz e a invertemos. Queremos revertê-lo, pois facilita a adição de vírgulas, dependendo do índice.
- Nós usamos o javascript
reduce
para recriar nossa string numérica. Após cada 3 números, queremos adicionar uma vírgula. - Quando tivermos nosso novo valor com as vírgulas, queremos revertê-lo. Então, dividimos novamente, invertemos a matriz de caracteres e nos juntamos a ela, que é o que retornamos
E agora que temos nossa commafy
função, vamos usá-lo. De volta para dentro src/pages/index.js
, vamos importar nossa função na parte superior da página:
import { commafy } from 'lib/util';
Então, no nosso dashboardStats
matriz, vamos substituir cada valor numérico por uma expressão e função ternárias que converterão nosso número, se disponível:
value: stats ? commafy(stats?.cases) : '-'
Esta linha verifica para ver se stats
existe. Se isso acontecer, nós commafy
a cases
valor. Se não existir, retornamos um -
para mostrar que não está disponível.
Depois de repetir esse processo para todos os nossos números, podemos salvar, recarregar a página e ver nossos números amigáveis!
Etapa 4: adicionar a data da última atualização
Por fim, queremos garantir que as pessoas fiquem informadas e entendam a última vez que esses dados foram atualizados. Felizmente, nossa API fornece uma data da última atualização para nós, então vamos usá-la!
Na parte inferior do nosso "rastreador" div
debaixo tracker-stats
, vamos adicionar o seguinte:
Last Updated: { stats?.updated }
Isso cria uma nova seção na qual simplesmente incluímos o updated
propriedade de nossas estatísticas. E se salvarmos e recarregarmos a página, poderemos ver a última data de atualização!
Mas como poderíamos entender qual é esse número, a menos que você seja o computador que rastreia esta postagem no blog? Então, vamos mudar para um formato legível por humanos, como fizemos com nossos números.
Dentro do nosso src/lib/util.js
arquivo, vamos adicionar outra função:
/** * friendlyDate * @description Takes in a date value and returns a friendly version */export function friendlyDate(value) { const date = new Date(value); return new Intl.DateTimeFormat('en', { year: 'numeric', month: 'short', day: '2-digit', hour: 'numeric', minute: 'numeric' }).format(date);}
Esta função cria um novo Date
objeto, em seguida, usa o javascript API internacional DateTimeFormat para convertê-lo em um formato legível e amigável!
Depois de salvo, vamos importá-lo ao lado do nosso commafy
função no topo da src/pages/index.js
:
import { commafy, friendlyDate } from 'lib/util';
Em seguida, podemos atualizar nosso código da mesma maneira que atualizamos nossos números:
Last Updated: { stats ? friendlyDate(stats?.updated) : '-' }
E se salvarmos e recarregarmos, vemos isso de uma maneira legível por humanos!
Finalmente, nossa "última atualização" deve se encaixar no restante do painel, então vamos adicionar mais alguns estilos. Dentro do nosso _tracker.scss
arquivo com o qual estávamos trabalhando anteriormente:
.tracker-last-updated { color: white; background-color: $blue-grey-900; padding: .8em 0; p { color: $blue-grey-300; font-size: .8em; text-align: center; margin: 0; }}
E quando pressionamos salvar e atualizar o navegador, temos as estatísticas do painel com a última atualização. 🎉
O que posso fazer a seguir?
Tornar os dados da dica de ferramenta do marcador amigáveis
Agora que temos a nossa mão commafy
e friendlyDate
funções, podemos reutilizar essas funções para limpar os dados nos pop-ups de marcadores do nosso país!
Use a função fetchTracker para pesquisar atualizações
Dentro do useTracker
gancho que criamos, exportamos uma função chamada fetchTracker
. Isso nos permite forçar uma solicitação à API para buscar novos dados. Para garantir que nosso mapa permaneça atualizado, mesmo quando alguém não atualizar a página, podemos criar um cronômetro em javascript para invocar regularmente essa função para atualizar nossos dados do painel.
Limpe as camadas do mapa antes de adicionar novamente as novas
No momento, não estamos limpando as camadas antigas antes de adicionar uma nova. Da maneira como o mapa é configurado, ele fica em camadas por cima. O que podemos fazer é que, antes de adicionarmos todas as nossas novas camadas, possamos limpar as antigas. Confira este commit para começar!
Deseja saber mais sobre mapas?
Você pode conferir alguns dos meus outros recursos para começar: