Cover Image for Criando uma Pokédex com Next.js - Parte 1

Criando uma Pokédex com Next.js - Parte 1

22 de setembro de 2022

Esse post é a parte 1 de 3 de posts ensinando a criar um projeto com Next.js e hospedando ele na Vercel


🎉 Live Demo

Fala pessoal! Como vocês estão? Como prometido, nesse post vou falar sobre como criar um projeto usando o framework front-end Next.js. Por ser um conteúdo um pouco extenso, vou dividir esse post em duas partes de desenvolvimento e uma terceira parte de como hospedar esse projeto na Vercel. Em breve eu posto a segunda parte.

O que é o Next.js?

Next.js é um framework para desenvolvimento frontent que usa como base o React. O que isso quer dizer? O React é uma biblioteca JavaScript criado pelo time do Facebook para a construção de interfaces modernas, e o Next.js é considerado um framework, pois adiciona diversas funcionalidades em cima do React. Você pode acessar a documentação oficial do Next.js clicando aqui.

Algumas funcionalidades do Next.js

  • Renderização estática pelo lado do servidor (server-side-rendering ou SSR);
  • Suporte ao Typescript
  • Tratamento de rotas automático
  • Fast refresh

Muitas funcionalidades serão mais perceptíveis quando nossa aplicação estiver em ambiente produtivo, pois o Next.js tem dois pontos que são mais relevantes. O primeiro é tornar nossa aplicação React mais performática já que ele fornece diversas funcionalidades que se fossemos usar o React puro, precisariamos instalar bibliotecas por fora e a outra é a indexação do nosso site através dos motores de busca.

Falando um pouco sobre a indexacão, quando usamos o React por padrão, toda nossa interface é montada pelo lado do cliente (browser). Então quando algum motor de busca, ou crawler, tenta indexar uma página feita com React, ele não espera que nossa aplicação faça o carregamentos do arquivos da página. Ou seja, essa busca não retorna nada ou sem as informações relevantes para que nossa aplicação seja indexada.

Para isso, o Next.js atua usando um servidor Node.js para gerar essa página estática, proporcionando assim, a entrega da página pronta para o browser, ou seja, todo o HTML, CSS e JS. Esse comportamento se chama server-side-rendering.

server side rendering with Next.js

Com essa funcionalidade, a página é retornada para o usuário toda montada. Pensando que esse usuário seja um motor de busca, todo o conteúdo da página retorna, facilitando assim a indexação.

Falando um pouco também sobre o roteamento, o Next.js se encarrega de fazer todo o tratamento de rotas automaticamente, então o que precisamos fazer é criar um arquivo com o nome da rota que queremos definir. Por exemplo, se queremos uma rota /blog, então basta criar um arquivo chamado blog.js. Se quisermos acessar um post do blog, exemplo /blog/meu-primeiro-post, então criamos um diretório chamado blog e dentro criamos um arquivo chamado [post].js. Note que o nome post está entre colchetes ([]), fazendo com que o sistema de roteamento do Next.js entenda como algo parâmetro dinâmico, já que ele muda de post para post. No final a estrutura deve ser essa:

└── pages
    └── blog.js

// ou

└── pages
    └── blog
        ├── index.js
        └── [post].js

O que vamos construir?

Nós vamos construir uma Pokédex. Para isso vamos usar uma API muito legal chamada PokéAPI, ela é gratuita e você pode explorar a documentação oficial dela aqui. Nessa primeira parte, vamos desenvolver apenas o layout da tela inicial, e na segunda parte vamos dinamizar o conteúdo através do consumo da API de Pokémons. Pra isso vamos usar o template básico gerado pelo CLI (command-line interface ou interface de linha de comando) do próprio Next.js.

Pré-requisitos

Não é necessário ser um especialista, mas é bom que você tenha ao menos um pouco de experiência com as tecnologias abaixo:

  • HTML
  • CSS
  • JavaScript
  • React

Além disso, verifique se você já tem o Node.js e o NPM instalados no seu computador. Para isso você pode rodar o seguinte comando no terminal:

node -v && npm -v

Se tudo der certo, você deverá ter uma saída parecida com essa:

v16.15.1 // Node.js
8.11.0 // npm

Obs.: A versão mínima do Node.js para usar o Next.js é a 12.22.0.

Caso você não tenha instalado no seu computador, é só baixar do site oficial e seguir o passo-a-passo de instalação.

Iniciando o projeto

Agora que já entendemos um pouco da tecnologia que vamos usar e do que vamos construir, podemos startar o projeto. Para isso, abra o terminal e navegue até o diretório que você deseja trabalhar e digite o seguinte comando (esse processo pode demorar um pouco):

npx create-next-app pokedex-nextjs

Rodando esse comando, você estará criando um projeto dentro do diretório que você estava, como citado no passo anterior, e você pode navegar até ele com o comando cd pokedex-nextjs.

Entendendo a estrutura

Antes de começarmos a desenvolver, vamos entender um pouco da estrutura gerada.

├── pages
│   └── api
├── public
├── styles
├── next.config.js
├── package.json
├── package-lock.json
└── README.md
  • pages: diretório onde ficam os arquivos de cada página que também funcionam como roteamento da aplicação;
    • api: uma api disponibilizada através do sistema de roteamento automático do Next.js;
  • public: diretório onde ficam os arquivos públicos da aplicação como imagens, ícones, etc;
  • styles: diretório onde ficam arquivos de estilização como css, scss, less, etc;
  • next.config.js: arquivo de configuração do Next.js da aplicação;
  • package.json: arquivo de configuração do Node.js, onde ficam os scripts, as dependências e demais informações de inicialização da aplicação JavaScript;
  • package-lock.json: arquivo de configuração onde ficam salvas as informações de versão, integridade e demais meta-dados das dependências da aplicação.

Desenvolvendo a tela inicial

Agora que já temos nossa estrutura pronta, vamos acessar o index.js, dentro do diretório pages e remover todo o código que vem por padrão e substituir pelo seguinte:

import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";

export default function Home() {
  const [pokemons, setPokemons] = useState([
    {
      name: "bulbasaur",
      id: 1,
      image:
        "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png",
      elementTypes: ["grass", "poison"],
    },
    {
      name: "ivysaur",
      id: 2,
      image:
        "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png",
      elementTypes: ["grass", "poison"],
    },
    {
      name: "venusaur",
      id: 3,
      image:
        "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png",
      elementTypes: ["grass", "poison"],
    },
  ]);

  return (
    <div className={styles.container}>
      <Head>
        <title>Pokédex</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <div className={styles.container}>
        <h1 className={styles.title}>Pokédex</h1>
        <div className={styles.pokedex}>
          {pokemons.map(({ name, id, image, elementTypes }) => (
            <a
              href={`pokemon/${name}`}
              key={id}
              className={`${styles.card} ${styles[elementTypes[0]]}`}
            >
              <Image
                className={styles["card-image"]}
                alt={name}
                src={image}
                width={150}
                height={150}
              />
              <h2 className={styles["card-title"]}>
                {id}. {name}
              </h2>
              <p className={styles["card-subtitle"]}>
                {elementTypes.join(" | ")}
              </p>
            </a>
          ))}
        </div>
      </div>
    </div>
  );
}

Com o básico do layout da tela inicial pronto, agora vamos mexer um pouco na estilização dos componentes em dois arquivos de css, ambos dentro do diretório styles. O primeiro deles é o globals.css, você deve remover todo o código que vem por padrão e substituir pelo seguinte:

@import url("https://fonts.googleapis.com/css2?family=Rubik&display=swap");

html,
body {
  background: #efefbb;
  background: linear-gradient(to right, rgb(197, 230, 236), rgb(239, 187, 230));
  color: #212121;
  margin: 0;
  font-family: rubik, san-serif;
  overflow-x: hidden;
}

Esse primeiro arquivo, vai estilizar um pouco a base da aplicação como cor de fundo, cor da letra, também vamos adicionar uma nova fonte. No segundo arquivo, o Home.module.css, você deve remover todo o código que vem por padrão e substituir pelo seguinte:

.container {
  padding: 2.5rem;
  margin: 0 auto;
}

.title {
  text-align: center;
  font-size: 3rem;
}

.pokedex {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  grid-gap: 1rem;
  padding-inline-start: 0;
}

.card {
  list-style: none;
  padding: 2rem;
  text-align: center;
  border-radius: 0.25rem;
  position: relative;
  transition: 0.2s;
  text-decoration: none;
  color: #212121;
}

.card:hover {
  box-shadow: 0 0 1rem 0.25rem rgba(0, 0, 0, 0.3);
}

.card-title {
  margin-bottom: 0;
  font-size: 2rem;
  font-weight: normal;
  position: relative;
  z-index: 2;
}

.card-subtitle {
  margin-top: 0.5rem;
  color: #666;
  position: relative;
  z-index: 2;
}

.card-image {
  background-color: #fff;
  padding: 1rem;
  border-radius: 0.25rem;
}

.steel {
  background-color: #f4f4f4;
}

.fire {
  background-color: #fddfdf;
}

.grass {
  background-color: #defde0;
}

.electric {
  background-color: #fcf7de;
}

.water,
.ice {
  background-color: #def3fd;
}

.ground {
  background-color: #f4e7da;
}

.rock {
  background-color: #d5d5d4;
}

.fairy {
  background-color: #fceaff;
}

.poison {
  background-color: #98d7a5;
}

.bug {
  background-color: #f8d5a3;
}

.dragon {
  background-color: #97b3e6;
}

.psychic {
  background-color: #eaeda1;
}

.flying {
  background-color: #f5f5f5;
}

.fighting {
  background-color: #e6e0d4;
}

.normal {
  background-color: #f5f5f5;
}

Antes de testarmos o nosso site no navegador, precisamos adicionar uma configuração no arquivo next.config.js. Essa configuração serve para podermos usar as imagens dos Pokémons que vem de um serviço externo, pois, por padrão o elemento de imagens do Next.js, <Image />, usa como base o diretório public para imagens, então devemos adicionar a seguinte configuração:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: ["raw.githubusercontent.com"],
  },
};

module.exports = nextConfig;

Dessa forma, podemos usar tranquilamente as imagens externas que não teremos problema. Bora rodar o projeto.

Testando no navegador

Para ver o resultado do que desenvolvemos até agora, vamos executar o seguinte comando no terminal: npm run dev. Se tudo ocorrer bem, uma mensagem parecida com essa deve aparecer:

> pokedex-nextjs@0.1.0 dev
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info  - SWC minify release candidate enabled. https://nextjs.link/swcmin
event - compiled client and server successfully in 400 ms (178 modules)
wait  - compiling...
event - compiled client and server successfully in 72 ms (178 modules)

Se você abrir o navegador no endereço http://localhost:3000, deverá ver a seguinte tela:

pokédex screen

Conclusão

Bom, nesse primeiro post aprendemos um pouco sobre o que é o Next.js e um pouco das suas incríveis funcionalidades que salvam as vida do desenvolvedor e tornam a experiência de desenvolvimento muito prazerosa. E claro, se você teve algum problema ou ficou com alguma dúvida, não esqueça de me mandar uma email, pra que eu possa te ajudar. 🙃

No próximo post, vamos usar a PokéAPI para mostrar os Pokémons de forma dinâmica e usar o roteamento para navegarmos para a tela de detalhes do Pokémon. Até mais 👋.

anteriorpróximo