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.

coronavirus covid 19 dashboard map stats
Demonstração de mapa do Coronavirus (COVID-19) com estatísticas do painel

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.

coronavirus map tutorial country markers
Painel do mapa de coronavírus (COVID-19)

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 e useState 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 argumento api 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 nossa fetchTracker função para fazer a solicitação. Temos apenas uma dependência de api. Isso significa que a função será acionada apenas na primeira vez e sempre que o api 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 nossa fetchTracker 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.jsremova 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.

code diff map effect countries data
Código diff mostrando atualização para mapear o efeito

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!

console log coronavirus stats 1
Usando console.log para mostrar estatísticas do Coronavirus (COVID-19)

Siga junto com o commit!

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 componente dentro deste rastreador
  • 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:

adding coronavirus stats to page
Adicionando as primeiras estatísticas à página

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:

adding coronavirus case statistics to map dashboard
Incluindo estatísticas de caso no painel

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.

Siga junto com 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!

coronavirus dashboard stats with readable stats
Formatando as estatísticas para serem legíveis por humanos

Siga junto com o commit!

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!

coronvirus dashboard last updated
Adicionando a última atualização ao painel

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!

coronvirus dashboard last updated formatted 1
Formatando a última data atualizada

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. 🎉

coronavirus dashboard formatted styled
Painel final com data de atualização durada e formatada

Siga junto com o commit!

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:

Siga-me para mais Javascript, UX e outras coisas interessantes!