Skip to content

Latest commit

 

History

History
1840 lines (1391 loc) · 53.9 KB

File metadata and controls

1840 lines (1391 loc) · 53.9 KB

Next.js

É a versão framework do React, o React é a biblioteca JavaScript mais popular para aplicação front-end do mundo e o Next.js acrescenta ao React uma estrutura, e uma série de funcionalidades. Framework trás essa ideia de trazer uma estrutura pré-pronta para que possamos personalizar e apartir daí começar a desenvolver nossas aplicações.

Criando um projeto com Nest.js

  • Dentro da pasta do projeto, vamos rodar o comando(mais recomendado atualmente usar o npx):
npx create-next-app fundamentos
                     [nome-aplicação]

npx: Comando que vai se encarregar de baixar uma dependência que vamos usar apenas de forma temporária. Ele baixa essa dependência, executa o que tem que ser executado e depois exclui ela. Desse modo, não instalamos as dependências de forma global, evitando ocupar espaço na máquina.

create-next-app: Dependência para criar um projeto.

  • Ao finalizar a criação ele informa no terminal os próximos passos. Primeiro, entrar na pasta da aplicação:
cd fundamentos
   [nome-pasta-aplicação]
  • Segundo, rodar o comando para iniciar o projeto:
yarn dev ou npm run dev

Configurações do projeto

Dentro do vscode, podemos notar que foram criados os seguintes diretórios no projeto:

.next
node_modules
pages
public
styles

Vamos criar uma pasta src na raiz do projeto. E mover as pastas pages e styles para dentro de src

  • Agora, vamos parar a aplicação
ctrl + c
  • E rodar novamente, para que a página seja recarregada:
yarn dev ou npm run dev
  • Outra coisa, que podemos nos atentar é que dentro da pasta pages temos dois arquivos:
_app.js
index.js
  • Eles são arquivos javascript só que dentro deles temos códigos jsx(javascript com react), desse modo, podemos mudar a extensão desses arquivos para que o vscode consiga lidar melhor com eles.

Estrutura de pastas

  • No momento vamos ressaltar 3 pastas que o next.js cria no nosso projeto:
public
pages
styles
  • Sabemos que qualquer aplicação web se baseia em trẽs tecnologias: HTML, CSS e JavaScript. Dentro da pasta styles temos os arquivos de CSS. E podemos notar que temos dois padrões de nomenclatura, um padrão que é simplesmente o nome-do-arquivo.css que é utilizado para modificar a aplicação como um todo, de forma global(ex.: globals.css) e o outro padrão que é nome-do-arquivo.module.css que é o CSS escopado/modularizado esse CSS vai impactar componentes especificos(ex.: Home.module.css).

  • Já na pasta public vamos ter os arquivos de imagem, fonte, video, gif. Dentro desse diretório, podemos criar subpastas, ex.: imagens, fonts... e esses arquivos serão servidos de forma estática para a aplicação.

  • Como viemos do React, vamos sentir falta da página index.html que vem por padrão, e se precisarmos personalizar o index, existem outras formas de fazer... assunto para outro momento.

  • Na pasta pages será a pasta que vamos acabar trabalhando a maior parte do tempo... dentro dela, temos o arquivo index.jsx e esse arquivo está sendo carregado no localhost:3000 e temos também uma subpasta chamada api e dentro dela temos o arquivo chamado hello.js e se abrirmos a página localhost:3000/api/hello vamos ver os dados dessa página. Ou seja, o next.js é um framework fullstack, ele vai dar a parte do front como também vai permitir a criação da API dentro dele.

Primeiro componente & rotas

  • Primeiramente vamos excluir o arquivo index.jsx que se encontra dentro do diretório src/pages para aprendermos a criar ele do zero e entendermos como funciona a criação de componentes dentro do next.js.

  • No novo arquivo index.jsx vamos criar uma função chamada Inicio e ela vai retornar/return a string "Início":

function Inicio() {
  return "Início"
}
  • Nesse momento, não vamos conseguir ver essa informação/retorno "Início" na tela, pois foi gerado o seguinte problema: The default export is not a React Component in page: "/", ou seja, ele tentou acessar um componente, mais esse componente precisa ser exportado. Portanto, vamos voltar na função, e antes dela colocar a palavra export, mas isso também não será suficiente, pois precisamos exportar por padrão então devemos colocar export default, desse modo o retorno do componente funcional irá aparecer na tela:
export default function Inicio() {
  return "Início"
}
  • Antes de prosseguirmos vale resaltar, se criarmos novos arquivos dentro da pasta pages, por exemplo um arquivo chamado teste.jsx que vai receber um componente funcional igual ao que criarmos para index.jsx cujo o retorno vai ser a string "Teste":
export default function Teste() { // é importante exportar por padrão, para que ele consiga ler e executar esse função
  return "Teste"
}
  • Só o fato de criarmos um novo arquivo dentro da pasta pages faz com que tenhamos acesso a url localhost:3000/nome-arquivo, nesse caso a url localhost:3000/teste, e ela vai mostrar o conteúdo desse arquivo teste.jsx. Então, a primeira coisa que devemos lembrar e entender... que o Next.js é um framework que foca bastante em não precisarmos configurar as coisas, ou seja, vamos usar uma série de convenções e essas convenções vão nos ajudar no desenvolvimento da aplicação. E uma convenção é o fato que se criarmos um arquivo dentro da pasta pages, automáticamente temos acesso ao conteúdo desse arquivo em uma url seguindo o mesmo caminho de pastas desse arquivo.

Conhecendo o JSX

É uma extensão de sintaxe para JavaScript. É recomendado usar JSX com o React. JSX pode lembrar uma linguagem de template, mas que vem com todo o poder do JavaScript. Nada mais é que código JavaScript com "cara" de HTML.

  • Dentro do Next.js para utilizarmos o JSX não é necessário realizar o import do React no arquivo. Podemos usá-lo diretamente assim:
export default function Inicio() {
  return (
    <div>
      <h1>Fundamentos de Next.js & React</h1>
      <h2>Vamos estudar esse framework!</h2>
    </div>
  )
}

Integração JavaScript/JSX

Como acessar o JavaScript puro dentro de um trecho JSX? Sim, usando um par de chaves {}. Quando usamos par de chaves significa que dentro podemos usar código JavaScript. Exemplo:

export default function Jsx() {
  const a = 2
  const b = 3
  const subtitulo = <h2>Teste</h2>
  
  return (
    <div>
      <h1>JSX é um conceito central</h1>
      {subtitulo} {/* acessando o trecho JSX da constante subtitulo */}
      <h3>{a * b}</h3> {/* vai ser feito a multiplicação e o resultado vai ser renderizado em tela */}
    </div>
  )
}

CSS Global

O CSS global da nossa aplicação fica dentro da pasta styles no arquivo globals.css e esse arquivo está sendo referênciado dentro do arquivo _app.jsx que fica dentro da pasta pages:

import '../styles/globals.css' // referẽncia ao arquivo CSS global da aplicação

function MyApp({ Component, pageProps }) { // função que renderiza as páginas da aplicação
  return <Component {...pageProps} />
}

export default MyApp
  • No arquivo globals.css podemos mudar o background-color para um tom de cinza e a cor da fonte/color para um tom de branco, desse modo deixando a leitura mais agradável... e essas alterações vão refletir nos outros componentes também:
html,
body {
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
  Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;

  padding: 0;
  margin: 0;

  background-color: #222;
  color: #eee;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}
  • Podemos criar também outra folha de estilo para a aplicação, exemplo app.css e inserir essas novas personalizações dentro desse arquivo, tirando do globals:
html,
body {
  background-color: #222;
  color: #eee;
}
  • E para que essas propriedades sejam aplicadas globalmente na nossa aplicação, vamos referênciar esse arquivo app.css dentro do arquivo que renderiza as páginas da aplicação(_app.js):
// Local para importar css globais(podemos ter mais de um)
import '../styles/globals.css'
import '../styles/app.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

CSS Modularizado

  • Podemos excluir o arquivo Home.module.css, pois não iremos usar ele nessa aplicação.

  • Vamos criar um novo componente no diretorio src/pages chamado estiloso.jsx. Esse componente vai ser um componente funcional:

export default function Estiloso() {
  return (
    <div>
      <h1>Componente para teste de CSS Modularizado</h1>
    </div>
  )
}
  • Agora vamos aplicar estido a esse componente. Podemos criar o arquivo CSS desse componente dentro da pasta styles com o nome Estiloso.module.css e desse arquivo podemos criar as classes CSS que acharmos necessário. Vamos criar uma classe com o nome roxo que vai conter a propriedade background-color com um tom de roxo e a color de fonte um tom de branco:
.roxo {
  background-color: #542481;
  color: #fff;
}
  • Em seguida, vamos importar essa folha de estilo dentro do componente que ela pertence(estiloso.jsx). Dentro de estiloso.jsx vamos referênciar esse arquivo CSS(Estiloso.module.css) como styles:
import styles from '../styles/Estiloso.module.css'

export default function Estiloso() {
  return (
    <div>
      <h1>Componente para teste de CSS Modularizado</h1>
    </div>
  )
}
  • Agora, podemos aplicar a classe CSS roxo dentro do componente(na div) com a propriedade className do jsx... mas para acessarmos esse estilo modularizado dentro do componente temos que referênciar dentro de um par de chaves/{} referencia-arquivo-css.class-name, nesse caso fica assim styles.roxo:
import styles from '../styles/Estiloso.module.css'

export default function Estiloso() {
  return (
    <div className={styles.roxo}>
      <h1>Componente para teste de CSS Modularizado</h1>
    </div>
  )
}

Usando Componente

  • Dentro de src vamos criar uma pasta chamada components e dentro dela vamos criar um componente chamado Cabecalho.jsx e vamos defini-lo como um componente funcional:
export default function Cabecalho() {
  return (
    <header>
      <h1>Fundamentos de Next.js & React</h1>
    </header>
  )
}
  • E vamos usar esse componente dentro de uma página. Para isso, vamos criar um arquivo chamado exemplo.jsx dentro de src/pages. E nesse arquivo, vamos criar um componente funcional e exportar por padrão, e nele vamos importar e retornar a intância jsx do componente Cabecalho:
import Cabecalho from "../components/Cabecalho";

export default function Exemplo() {
  return (
    <Cabecalho />
  )
}

Propriedade de Componentes

  • Agora, vamos entender como passar para um compentente uma propriedade, a fim de personalizarmos ele. Primeiramente, em exemplo.jsx vamos duplicar a referência ao componente Cabeçalho a fim de reaproveitarmos esse componente, mas vale resaltar que devemos envolve-los por um elemento(se não irá ocorrer um erro), pode ser uma div, table ou pelo proprio React.Fragment que foi feito para agrupar uma lista de componentes filhos sem adicionar nós extras ao DOM:
import Cabecalho from "../components/Cabecalho";

export default function Exemplo() {
  return (
    <div>
      <Cabecalho />
      <Cabecalho />
    </div>
  )
}
  • Vamos supor que queremos passar o título/h1 desse componente Cabecalho de forma personalizada... então dentro dele vamos receber um parâmetro chamado props. E podemos notar através do console que props é um objeto vazio:
export default function Cabecalho(props) {
  console.log(props)
  return (
    <header>
      <h1>Fundamentos de Next.js e React</h1>
    </header>
  )
}
  • E se no componente exemplo.jsx dentro da referência ao componente Cabecalho passarmos uma propriedade chamada titulo com o texto que queremos como titulo para eles:
import Cabecalho from "../components/Cabecalho";

export default function Exemplo() {
  return (
    <div>
      <Cabecalho titulo="Título 1"/>
      <Cabecalho titulo="Título 2"/>
    </div>
  )
}
  • Podemos notar através do console que o objeto props contém essas informações de titulo e podemos recupera-las atraves acessando o atributo que queremos recuperar de dentro do objeto props(props.titulo):
export default function Cabecalho(props) {
  console.log(props)
  return (
    <header>
      <h1>{props.titulo}</h1>
    </header>
  )
}

Navegação entre Componentes

  • Vamos entender uma funcionalidade do Next.js para navegação entre componentes via Link. Vamos no arquivo index.js e vamos excluir o que tem dentro da div e vamos importar o Link de dentro do next/link:
import Link from "next/link"

export default function Inicio() {
  return (

  )
}
  • E com isso, vamos criar um Link e dentro desse link vamos definir o atributo obrigatório href que nada mais é do que o caminho para acessar o link que queremos(link do componente que foi criado pelo next) e dentro do Link vamos definir o nome dele(nome do componente):
import Link from "next/link"

export default function Inicio() {
  return (
      <Link href="/estiloso">
        Estiloso
      </Link>
  )
}
  • E dentro desse componente Estiloso podemos criar um Link para voltar para o index. Vamos importar Link de next/link e criar o link para o / com o nome Voltar:
import Link from 'next/link'
import styles from '../styles/Estiloso.module.css'

export default function Estiloso() {
  return (
    <div className={styles.roxo}>
      <Link href="/">Voltar</Link>

      <h1>Componente para teste de CSS Modularizado</h1>
    </div>
  )
}

Componente Layout

  • Dentro de src/components vamos criar um componente que vai representar o layout da página, ele irá se chamar Layout. Dentro desse arquivo vamos criar um componente funcional:
export default function Layout(props) {
  return (
    <div>
      
    </div>
  )
}
  • Em seguida, vamos importar o Link do next/link e vamos definir um link que irá voltar para o home da nossa aplicação:
import Link from "next/link"

export default function Layout(props) {
  return (
    <div>
      <Link href="/">Voltar</Link>

    </div>
  )
}
  • E depois vamos passar um conteúdo para esse componente Layout... como assim? Queremos pegar o conteúdo de outro componente e renderizar na tela. Por exemplo, vamos importar o componente Layout que contém o link de voltar para o home dentro do componente Estiloso e vamos envolver o conteúdo desse componente Estiloso com o componente Layout que importamos, para ele ter sem precisarmos criar manualmente o botão/link de voltar para o home:
import Layout from "../components/Layout"
import styles from "../styles/Estiloso.module.css"

export default function Estiloso() {
  return (
    <Layout>
      <div className={styles.roxo}>
        <h1>Componente para teste de CSS Modularizado</h1>
      </div>
    </Layout>
  )
}
  • Só que, se acessarmos a url do componente Estiloso vamos notar que só está sendo renderizado o que está no componente Layout, ou seja, o link voltar. Isso ocorre, pois é necessário informar dentro do componente Layout que desejamos renderizar o conteúdo que foi passado dentro dele através dos componentes filhos(props.children):
import Link from "next/link"

export default function Layout(props) {
  return (
    <div>
      <Link href="/">Voltar</Link>
      {props.children}
    </div>
  )
}
  • Vamos criar uma folha de estilo para layout dentro de src/styles com o nome Layout.module.css e vamos referênciar esse arquivo como styles dentro do seu componente:
import styles from "../styles/Layout.module.css"

import Link from "next/link"

export default function Layout(props) {
  return (
    <div>
      <Link href="/">Voltar</Link>
      {props.children}
    </div>
  )
}
  • Desse modo, podemos criar uma classe e referênciar ela como styles.nome-classe, que nesse caso o nome da classe será layout:
import styles from "../styles/Layout.module.css"

import Link from "next/link"

export default function Layout(props) {
  return (
    <div className={styles.layout}>
      <Link href="/">Voltar</Link>
      {props.children}
    </div>
  )
}
  • E podemos selecionar essa classe no arquivo Layout.module.css e aplicar algumas propriedades de estilo:
.layout {
  
}
  • Dentro dela vamos aplicar uma altura/height de 100vh para que o componente ocupe todo o espaço disponível, além disso, vamos definir o display como flex e alterar o flex-direction para column:
.layout {
  display: flex;
  flex-direction: column;

  height: 100vh;
}
  • Feito isso, vamos voltar no arquivo do componente Layout e vamos dividir o componente em duas partes, uma que vai conter o cabeçalho com os links e outra parte que vai conter o conteúdo, ambas as partes terão suas próprias classes CSS:
import styles from "../styles/Layout.module.css"

import Link from "next/link"

export default function Layout(props) {
  return (
    <div className={styles.layout}>
      <div className={styles.cabecalho}>
        <Link href="/">Voltar</Link>
      </div>
      <div className={styles.conteudo}>
        {props.children}
      </div>
    </div>
  )
}
  • Em seguida, e essa classe cabecalho que criamos para o cabeçalho vamos selecionar ela dentro da folha de estilo e iremos aplicar um background-color e mudar o display para flex e o justify-content como flex-end para alinhar o texto do cabeçalho todo para a direita, e um padding no eixo y(vertical) de 10px e no eixo x(horizontal) de 20px:
.layout {
  display: flex;
  flex-direction: column;

  height: 100vh;
}

.cabecalho {
  display: flex;
  justify-content: flex-end;

  padding: 10px 20px;

  background-color: #777;
}
  • E um ponto importânte sobre o componente Link que gera os links(que se encontra dentro do Layout) é que por trás dos panos é gerado um link/tag a automáticamente, então podemos usar essa tag a para aplicarmos estilo CSS nele... e vamos aplicar um background-color e aplicar um padding no eixo y(vertical) de 5px e no eixo x(horizontal) de 12px, além disso, definir uma border-radius de 5px:
.layout {
  display: flex;
  flex-direction: column;

  height: 100vh;
}

.cabecalho {
  display: flex;
  justify-content: flex-end;

  padding: 10px 20px;

  background-color: #777;
}

.cabecalho a {
  background-color: coral;

  padding: 5px 12px;
  border-radius: 5px;
}
  • Em seguida, vamos usar a classe conteudo que criamos para o conteúdo, iremos aplicar um padding de 25px em todas as direções:
.layout {
  display: flex;
  flex-direction: column;

  height: 100%;
}

.cabecalho {
  display: flex;
  justify-content: flex-end;

  padding: 10px 20px;

  background-color: #777;
}

.cabecalho a {
  background-color: coral;

  padding: 5px 12px;
  border-radius: 5px;
}

.conteudo {
  padding: 25px;
}
  • Vamos voltar para o arquivo Layout.jsx e vamos inserir um texto/titulo no cabeçalho, e vamos receber ele via props e se não for passado nenhum parâmetro para esse titulo por padrão vai ser inserido no h1 o texto "Mais um exemplo":
import styles from "../styles/Layout.module.css"

import Link from "next/link"

export default function Layout(props) {
  return (
    <div className={styles.layout}>
      <div className={styles.cabecalho}>
        <h1>{props.titulo ?? "Mais um exemplo"}</h1>
        <Link href="/">Voltar</Link>
      </div>
      <div className={styles.conteudo}>
        {props.children}
      </div>
    </div>
  )
}
  • E dentro do arquivo do componente Estiloso vamos passar via props o titilo através do componente Layout(componente pai):
import Layout from "../components/Layout"
import styles from "../styles/Estiloso.module.css"

export default function Estiloso() {
  return (
    <Layout titulo="Exemplo de CSS Modularizado">
      <div className={styles.roxo}>
        <h1>Componente para teste de CSS Modularizado</h1>
      </div>
    </Layout>
  )
}
  • E na folha de estilho de Layout onde tem a class cabecalho e h1 vamos zerar a margin e o tamanho da fonte font-size vai ser 1.4rem:
.layout {
  display: flex;
  flex-direction: column;

  height: 100%;
}

.cabecalho {
  display: flex;
  justify-content: flex-end;

  padding: 10px 20px;

  background-color: #777;
}

.cabecalho h1 {
  margin: 0;

  font-size: 1.4rem;
}

.cabecalho a {
  background-color: coral;

  padding: 5px 12px;
  border-radius: 5px;
}

.conteudo {
  padding: 25px;
}
  • E vamos alterar o justify-content do cabecalho para space-between, desse modo ele vai organizar os elementos um mais a esquerda(h1) e outro mais a direita(Link):
.layout {
  display: flex;
  flex-direction: column;

  height: 100%;
}

.cabecalho {
  display: flex;
  justify-content: space-between;

  padding: 10px 20px;

  background-color: #777;
}

.cabecalho h1 {
  margin: 0;

  font-size: 1.4rem;
}

.cabecalho a {
  background-color: coral;

  padding: 5px 12px;
  border-radius: 5px;
}

.conteudo {
  padding: 25px;
}

Componente Navegador

  • Temos os nossos Link dentro do index, só que queremos aplicar estilo nele, o ideial é que a gente o coloque dentro de um componente, para isso vamos criar um componente chamado Navegador dentro de src/components, e esse componente será um componente funcional:
export default function Navegador(props) {
  return (
    
  )
}
  • E vamos encapsular dentro desse componente o Link que temos dentro de index.jsx:
import Link from "next/link"

export default function Navegador(props) {
  return (
      <Link href="/estiloso">
        Estiloso
      </Link>
  )
}
  • E dentro do arquivo index.jsx ao invés de chamar diretamente o Link vamos chamar esse componente Navegador que contém os links:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div>
      <Navegador />
    </div>
  )
}
  • Agora, iremos trabalhar com as propriedades e aprimeira coisa que vamos modificar é que agora vamos receber o href via props através do atributo destino, bem como o texto desse link via o atributo texto:
import Link from "next/link"

export default function Navegador(props) {
  return (
      <Link href={props.destino}>
        {props.texto}
      </Link>
  )
}
  • E vamos passar tanto o href quanto o texto do link via props onde estamos renderizado esse componente Navegador(no arquivo index):
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div>
      <Navegador destino="/estiloso" texto="Estiloso"/>
    </div>
  )
}
  • Em seguida, vamos criar uma folha de estilo para o componente Navegador dentro de src/styles chamado Navegador.module.css. E vamos referênciar esse arquivo CSS dentro de Navegador.jsx como styles:
import Link from "next/link"

import styles from "../styles/Navegador.module.css"

export default function Navegador(props) {
  return (
      <Link href={props.destino}>
        {props.texto}
      </Link>
  )
}
  • Agora temos a possibilidade de definir algumas classes. Vamos inserir uma div dentro do Link para aplicarmos uma classe chamada navegador(styles.navegador):
import Link from "next/link"

import styles from "../styles/Navegador.module.css"

export default function Navegador(props) {
  return (
      <Link href={props.destino}>
        <div className={styles.navegador}>
          {props.texto}
        </div>
      </Link>
  )
}
  • E vamos usar essa classe navegador dentro da folha de estilo Navegador.module.css. E vamos aplicar um background-color e um padding de 30px em todas as direções:
.navegador {
  background-color: blueviolet;

  padding: 30px;
}
  • E no arquivo index.css vamos definir alguns estilos interno dentro da propria propriedade style. Assim vamos mudar o display para "flex", e definir uma altura/height de 100vh e o justifyContent(não pode ter iffen dentro do arquivo JS) vamos mudar para "center" , o alingItems para "center" também, além disso, vamos informar que queremos permitir quebra de linha com a propriedade flexWrap como "wrap":
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX"/>
    </div>
  )
}
  • E vamos voltar dentro da folha de estilo do Navegador e definir uma margin de 10px para que os links não fiquem grudados. Além disso, podemos definir um border-radius de 8px para que o link tenha uma borda arredondada, além disso para quando passar o cursor do mouse sobre os links fique claro que se trata de um link/algo clicável, vamos inserir a propriedade cursor com o valor pointer:
.navegador {
  background-color: blueviolet;

  margin: 10px;
  padding: 30px;
  border-radius: 8px;

  cursor: pointer;
}
  • E a última coisa que vamos alterar no estilo é... ao invés de passarmos a cor do background-color diretamente, podemos voltar no componente Navegador e aplicar um estilo/style de forma dinâmica, caso ele receba a cor via props/props.cor ele vai usar a que ele recebe, caso contrário ele vai usar a cor padrão definida:
import Link from "next/link"

import styles from "../styles/Navegador.module.css"

export default function Navegador(props) {
  return (
      <Link href={props.destino}>
        <div className={styles.navegador} style={{
          backgroundColor: props.cor ?? "blueviolet"
        }}>
          {props.texto}
        </div>
      </Link>
  )
}
  • Agora, se voltarmos no arquivo index podemos além de passar o href e o texto via props para o destino, podemos também passar a cor para o background:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso" cor="cadetblue"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX" cor="brown"/>
    </div>
  )
}
  • Para finalizar, vamos envolver com o componente Layout(assim como fizemos com o componente estiloso) todos os outros componentes(jsx, exemplo) que estão sendo renderizados através do Link:
import Layout from "../components/Layout"
import Cabecalho from "../components/Cabecalho";

export default function Exemplo() {
  return (
    <Layout titulo="Usando Componente">
      <Cabecalho titulo="Título 1"/>
      <Cabecalho titulo="Título 2"/>
    </Layout>
  )
}
import Layout from "../components/Layout"

export default function Jsx() {
  const a = 2
  const b = 3
  const subtitulo = <h2>Teste</h2>
  
  return (
    <Layout titulo="Entendo o JSX">
      <h1>JSX é um conceito central</h1>
      {subtitulo} {/* acessando o trecho JSX da constante subtitulo */}
      <h3>{a * b}</h3> {/* vai ser feito a multiplicação e o resultado vai ser renderizado em tela */}
    </Layout>
  )
}

Navegação Simples

  • Uma coisa que podemos fazer é criar uma pasta dentro de src/pages chamada navegacao por exemplo, e dentro dela criar um arquivo index.jsx com um componente funcional chamado Navegacao:
import Layout from "../../components/Layout"

export default function Navegacao() {
  return (
    <Layout titulo="Exemplo de Navegação #01">
      <h1>Navegação #01</h1>
    </Layout>
  )
}
  • E quando formos referênciar a url desse componente dentro de src/pages/index.jsx em um novo componente Navegador podemos acessar diretamente através de /navegacao, não sendo necessário acessar por navegacao/index, pois só o "/" acessa diretamente o index, como fazemos com a home/index principal da nossa aplicação:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso" cor="cadetblue"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX" cor="brown"/>
      <Navegador destino="/navegacao" texto="Navegação #01" cor="green"/> {/*como se destino fosse assim: destino="/navegacao/index"*/}
    </div>
  )
}

Navegação Dinâmica/Por id

  • A navegação dinâmica é últil quando queremos acessar por exemplo um cliente por código. Para entendermos melhor, vamos criar dentro de src/pages uma pasta chamada cliente e dentro dela vamos criar um arquivo [código].jsx(o par de chaves é para deixar a url desse código dinâmica e o valor dentro do par de chaves vai ser o nome do parâmetro que ele vai receber). Em seguida, dentro dele vamos criar um componente funcional:
export default function ClientePorCodigo(props) {
  return (
    
  )
}
  • Dentro desse componente vamos importar o componente Layout e referenciar passando o atributo titulo para ele:
import Layout from "../components/Layout"

export default function ClientePorCodigo(props) {
  return (
    <Layout titulo="Navegação dinâmica">

    </Layout>
  )
}
  • E dentro dele vamos criar um span para exibir o código desse cliente:
import Layout from "../components/Layout"

export default function ClientePorCodigo(props) {
  return (
    <Layout titulo="Navegação dinâmica">
      <span>Código = ?????</span>
    </Layout>
  )
}
  • E no arquivo index.jsx vamos duplicar o componente Navegador e referenciar a url desse novo componente como _/cliente/1, o 1 será o código do cliente:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso" cor="cadetblue"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX" cor="brown"/>
      <Navegador destino="/navegacao" texto="Navegação #01" cor="green"/> 
      <Navegador destino="/cliente/1" texto="Navegação #02" cor="pink"/> 
    </div>
  )
}
  • E como podemos acessar esse valor, esse código do cliente que está sendo enviado pela rota? Vamos importar o hook useRouter de dentro do nex/router e ele irá nos ajudar a ter acesso ao valor. Vamos criar uma constante chamada router e ela irá receber o useRouter():
import Layout from "../../components/Layout"

import { useRouter } from "next/router"

export default function ClientePorCodigo(props) {
  const router = useRouter()
  
  return (
    <Layout titulo="Navegação dinâmica">
      <span>Código = ?????</span>
    </Layout>
  )
}
  • Se olharmos no console o que essa instância router está retornando, podemos notar que está retornando um objeto e que o código está dentro do query no atributo codigo, desse modo podemos acessar o valor do codigo assim router.query.codigo:
import Layout from "../../components/Layout"

import { useRouter } from "next/router"

export default function ClientePorCodigo(props) {
  const router = useRouter()
  console.log(router)
  
  return (
    <Layout titulo="Navegação dinâmica">
      <span>Código = {router.query.codigo}</span>
    </Layout>
  )
}

Componente com Estado

  • Para entendermos melhor, vamos criar um componente chamdo estado.jsx dentro de src/pages e esse componente vai ser um componente funcional:
import Layout from "../components/Layout"

export default function Estado(props) {
  return (
    <Layout titulo="Componente com Estado">
      
    </Layout>
  )
}
  • E em seguida, no arquivo index da aplicação vamos criar mais um componente Navegador o qual vai receber no atributo destino a url /estado:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso" cor="cadetblue"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX" cor="brown"/>
      <Navegador destino="/navegacao" texto="Navegação #01" cor="green"/> 
      <Navegador destino="/cliente/1" texto="Navegação #02" cor="hotpink"/> 
      <Navegador destino="/estado" texto="Componente com Estado" cor="coral"/> 
    </div>
  )
}
  • Agora, vamos aprendender a definir um componente com estado interno... Vamos usar o hook useState e para isso vamos importar o hook useState do React. Agora conseguimos criar estado dentro do nosso componente, mas ao invés de simplesmente criarmos uma variável colocando o valor dela, vamos chamar o useState e passar o valor inicial:
import { useState } from "react"

import Layout from "../components/Layout"

export default function Estado(props) {

  const state = useState(0)

  return (
    <Layout titulo="Componente com Estado">

    </Layout>
  )
}
  • Só que essa função vai retornar um array com duas possições, a primeira possição vai ser o valor inicial e a segunda posição vai ser uma função que vai ser usada para alterar esse valor. Como bem sabemos podemos usar atribuição via desestruturação (destructuring assignment). Ex.: const [a, b] = [1, 2], fica assim, a=1 e b=2. Desse modo, vamos usar o destructuring para receber os dois valores do array que useState retorna:
import { useState } from "react"

import Layout from "../components/Layout"

export default function Estado(props) {

  const [state, setState] = useState(0)

  return (
    <Layout titulo="Componente com Estado">

    </Layout>
  )
}
  • E para usarmos a função(setState) que altera o valor de state... vamos criar uma função incrementar e essa função vai chamar a função setState que vai pegar valor atual(state) + 1:
import { useState } from "react"

import Layout from "../components/Layout"

export default function Estado(props) {

  const [state, setState] = useState(0)

  function incrementar() {
    setState(state + 1)
  }

  return (
    <Layout titulo="Componente com Estado">

    </Layout>
  )
}
  • Agora, para visualizarmos a alteração acontecendo... vamos criar uma div e vamos interpolar o valor de state:
import { useState } from "react"

import Layout from "../components/Layout"

export default function Estado(props) {

  const [state, setState] = useState(0)

  function incrementar() {
    setState(state + 1)
  }

  return (
    <Layout titulo="Componente com Estado">
      <div>{state}</div>
    </Layout>
  )
}
  • Em seguida, vamos criar um button o qual vai chamar o evento onClick quando ele for acionado. E esse evendo onClick irá chamar chamar a função de incrementar:
import { useState } from "react"

import Layout from "../components/Layout"

export default function Estado(props) {

  const [state, setState] = useState(0)

  function incrementar() {
    setState(state + 1)
  }

  return (
    <Layout titulo="Componente com Estado">
      <div>{state}</div>
      <button onClick={incrementar}>Incrementar</button>
    </Layout>
  )
}

Usando API #01

A priori vamos trabalhar com o arquivo hello.js que encontramos dentro de src/pages/api. E uma coisa que vamos mexer nesse arquivo, é retornar uma informação metodo que é exatamente o método http que foi utilizado para fazer a requisição. Essa é uma das farmas dentro da API que conseguimos a partir de uma única URL tratar diferentes tipos de requisições(GET, POST, PUT...):

export default function handler(req, res) {
  res.status(200).json({ 
    metodo: req.method,
    name: 'John Doe' 
  })
}
  • Agora, vamos criar dentro de pages/api uma pasta chamada clientes/clients e dentro dela um arquivo chamado index.js;

  • Dentro desse arquivo que criamos no passo anterior, vamos criar uma funcão handle que vai receber como parãmetro a requisiçaõ/req e a resposta/res e vamos exportá-la por padrão/export default:

export default function handler(req, res) {
  
}
  • Normalmente vamos precisar ao menos usar a res para retornar algo para quem fez a requisição, vamos retornar a resposta com o status code 200 (res.json(200) e vamos usar o .send() no final para que essa mensagem seja enviada:
export default function handler(req, res) {
  res.status(200).send()
}
  • Também podemos retornar um JSON com os dados do cliente(res.status(200).json({})):
export default function handler(req, res) {
  res.status(200).json({
    id: 3,
    nome: 'Nathallye',
    age: 23
  })
}
  • Podemos também usar estruturas condicionais para verificar qual o método e retornar de acordo com o que foi solicitado na requisição:
export default function handler(req, res) {
  if(req.method === 'GET') {
    handleGet(req, res) // caso o metodo seja igual a GET será chamada a função handleGET passando os parâmetros de requisição/req e resposta/res
  } 
}

function handleGet(re, res) { // nesse caso colocamos o retorno da requição GET em uma função própria
  res.status(200).json({
    id: 3,
    nome: 'Nathallye',
    age: 23
  })
}
  • E caso o método solicitado não esteja definido vamos retornar o status code 405(url não suportada):
export default function handler(req, res) {
  if(req.method === 'GET') {
    handleGet(req, res)
  } else {
    res.status(405).send()
  }
}

function handleGet(re, res) {
  res.status(200).json({
    id: 3,
    nome: 'Nathallye',
    age: 23
  })
}

Usando API #02

  • Para obtermos informações a partir da query(parâmetros passados na url) podemos criar um arquivo dentro de src/pages/api/clients com url dinâmica chamado [codigo].js os [] garantem que a url vai ser dinâmica. E dentro desse arquivo vamos definir uma função, do mesmo modo que já definimos anteriormente:
export default function handler(req, res) {
  res.status(200).json({

  })
}
  • Como vamos receber um código dinâmicamente, podemos retornar nesse json o codigo que vamos receber a partir requisição de dentro da query/req.query.codigo:
export default function handler(req, res) {
  // exemplo de requisição: GET Http://localhost:3000/api/clients/1
  res.status(200).json({
    codigo: req.query.codigo // retorno: {"codigo": "1"}
  })
}

Integração do Font-end com API

  • Para isso, vamos criar um arquivo chamado integracao.jsx dentro do diretório src/pages;

  • Dentro desse arquivo vamos criar um componente funcional chamdo Integracao, seguindo o mesmo padrão que já vimos/criamos anteriormente:

import Layout from "../components/Layout"

export default function Integracao() {
  return (
    <Layout>

    </Layout>
  )
}
  • E dentro desse componente, vamos acessar as informações que estão no Back-end(API), nesse caso só é um objeto, mas poderia ser um array de objetos. E para obtermos essas informações do back-end iremos trabalhar com assíncronismo... poderiamos instalar a biblioteca axel que é um cliente http que é o muito utilizado, mas nesse caso vamos utilizar o proprio fetch para obter essas informações:
import Layout from "../components/Layout"

export default function Integracao() {

  fetch('')

  return (
    <Layout>

    </Layout>
  )
}
  • A url que precisamos para obter o cliente 1 é essa http://localhost:3000/api/clients/1, e vamos colocar dentro do fetch e isso vai retornar uma promisse, de tal forma se fizermos .then() vamos ter uma resposta .then(res) e assim podemos chamar a resposta e pegar o json dessa resposta .then(res => resp.json()) que é uma promisse:
import Layout from "../components/Layout"

export default function Integracao() {

  fetch('http://localhost:3000/api/clients/1')
    .then(resp => resp.json())

  return (
    <Layout>

    </Layout>
  )
}
  • E no segundo .then vamos ter acesso aos dados e podemos mostrar esses dados através do console.log. E tudo isso que está nesse fetch vai acontecer de forma assíncrona:
import Layout from "../components/Layout"

export default function Integracao() {

  fetch('http://localhost:3000/api/clients/1')
    .then(resp => resp.json())
    .then(dados => console.log(dados))

  return (
    <Layout>

    </Layout>
  )
}
  • Agora, dentro de src/pages/index.jsx e vamos criar um link para conseguirmos acessa esse componente integracao:
import Navegador from "../components/Navegador"

export default function Inicio() {
  return (
    <div style={{
      display: "flex",
      justifyContent: "center",
      alignItems: "center",
      flexWrap: "wrap",
      height: "100vh"
    }}>
      <Navegador destino="/estiloso" texto="Estiloso" cor="cadetblue"/>
      <Navegador destino="/exemplo" texto="Exemplo"/>
      <Navegador destino="/jsx" texto="JSX" cor="brown"/>
      <Navegador destino="/navegacao" texto="Navegação #01" cor="green"/> 
      <Navegador destino="/cliente/1" texto="Navegação #02" cor="hotpink"/> 
      <Navegador destino="/estado" texto="Componente com Estado" cor="coral"/> 
      <Navegador destino="/integracao" texto="Integração com API" cor="lightSteelBlue"/> 
    </div>
  )
}
  • E vamos criar uma tabela/ul e itens/li para inserir as informações:
import Layout from "../components/Layout"

export default function Integracao() {

  fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => console.log(dados))

  return (
    <Layout titulo="Integração com API">
      <ul>
        <li>Código: </li>
        <li>Nome: </li>
        <li>E-mail: </li>
      </ul>
    </Layout>
  )
}
  • Para ter essas informações definidas na nossa aplicação vamos precisar criar um estado o qual vai receber um objeto vazio [client, setClient] = useState({}):
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [client, setClient] = useState({})

  fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => console.log(dados))

  return (
    <Layout titulo="Integração com API">
      <ul>
        <li>Código: </li>
        <li>Nome: </li>
        <li>E-mail: </li>
      </ul>
    </Layout>
  )
}
  • E vamos chamar o setClient quando uma requisição for feita passando os dados recebidos que são justamente os dados dos clientes que recebemos na requisição:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [client, setClient] = useState({})

  fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))

  return (
    <Layout titulo="Integração com API">
      <ul>
        <li>Código: </li>
        <li>Nome: </li>
        <li>E-mail: </li>
      </ul>
    </Layout>
  )
}
  • E para chamarmos esse fetch a partir do click de um botão vamos colocar ele dentro de uma função a qual se chamará getClient:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }
  
  return (
    <Layout titulo="Integração com API">
      <ul>
        <li>Código: </li>
        <li>Nome: </li>
        <li>E-mail: </li>
      </ul>
    </Layout>
  )
}
  • E vamos criar um input do tipo number e um button que vai receber o evento de onClick o qual quando capturar o click do usuário no botão vai chamar a função getClient e quando esse cliente for obtido essa função vai chamar setClient passando os dados e irá alterar o estado do objeto cliente:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input type="number" />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: </li>
        <li>Nome: </li>
        <li>E-mail: </li>
      </ul>
    </Layout>
  )
}
  • Agora, vamos interpolar na tabela as informações do client que iremos obter através das requisições:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input type="number" />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}
  • Por hora, se clicarmos no "Obter Cliente" ele só irá trazer as informações do nosso cliente com o código 1, que especificações no fetch. Como fazemos para que inserindo um código no input seja retornado as informações do cliente com esse determinado código? Basicamente, vamos precisar criar um outro estado para guardarmos esse informação do codigo:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [codigo, setCodigo] = useState(1)
  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input type="number" />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}
  • E vamos associar codigo ao valor do input:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [code, setCode] = useState(1)
  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input type="number" value={code}/>
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}
  • E para conseguirmos alterar o valor de codigo vamos inserir o evento onChange para quando houver uma mudança ele vai pegar o próprio evento/e e obter o valor a partir de e.target.value e passar para o setCodigo para alterar o estado do objeto codigo:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [code, setCode] = useState(1)
  const [client, setClient] = useState({})

  function getClient() {
    fetch("http://localhost:3000/api/clients/1")
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input 
          type="number" 
          value={code}
          onChange={e => setCode(e.target.value)}
        />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}
  • Agora que temos o valor do código, podemos usar uma template string para considerar o uso no código na chamada da API:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [code, setCode] = useState(1)
  const [client, setClient] = useState({})

  function getClient() {
    fetch(`http://localhost:3000/api/clients/${code}`)
    .then(resp => resp.json())
    .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input 
          type="number" 
          value={code}
          onChange={e => setCode(e.target.value)}
        />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}
  • Outra possibilidade que temos é tratar a função como async, e com isso vamos escrever o código um pouco diferente. Vamos ter uma constante resposta/resp que recebe o await chamando o fetch que recebe a url da requisição, o await significa que ele tem que esperar e somente quando ele finalizar essa chamada ele passa para a próxima linha. E a próxima linha, teremos uma constante dados que recebe await retornando a resposta em json resp.json, e somente quando dados estiver pronto essa ele passa para a próxima linha, e por fim, irá chamar o setCliente passando os dados obtidos:
import { useState } from "react"
import Layout from "../components/Layout"

export default function Integracao() {

  const [code, setCode] = useState(1)
  const [client, setClient] = useState({})

  async function getClient() {
    const resp = await fetch(`http://localhost:3000/api/clients/${code}`)
    const dados = await resp.json()
    setClient(dados)

    // fetch(`http://localhost:3000/api/clients/${code}`)
    // .then(resp => resp.json())
    // .then(dados => setClient(dados))
  }

  return (
    <Layout titulo="Integração com API">
      <div>
        <input 
          type="number" 
          value={code}
          onChange={e => setCode(e.target.value)}
        />
        <button onClick={getClient}>Obter Cliente</button>
      </div>

      <ul>
        <li>Código: {client.codigo}</li>
        <li>Nome: {client.nome}</li>
        <li>E-mail: {client.email}</li>
      </ul>
    </Layout>
  )
}

Modelos de Pré-renderização

Documentação: https://nextjs.org/docs/basic-features/pages.

Na documentação do Next.js em recuros básicos, encontramos informações do que ele chama de pre-rendering e ele informa que por padrão o Next.js pré-renderiza cada uma das páginas da aplicação. E ele trabalha com duas formas de pré-renderizações, que são renderizações que acontecem do lado do servido e isso gera um impacto de desempenho muito grande.

  • Conteúdo gerado do lado do cliente:

Nessa imagem temos o lado do cliente/C e o lado do servidor/S, quando temos o conteúdo gerado do lado do cliente básicamente o que vai acontecer é que do lado do cliente vai ser feita uma requisição para o servidor, o servidor vai retornar uma página HTML. E dentro dessa página HTML vai ter um código JavaScript e esse código JS será responsável por gerar todo o conteúdo dinâmicamente dentro do browser do usuário. Esse é o cenário que precisamos ter apenas uma única página HMTL, pois estamos trabalhando com aplicação SPA(Single Page Application/ Aplicativo de página única):

image

Esse modelo também é suportado pelo Next.js, mas não cai em nenhum desses dois cenários que ele chama de pre-rendering.

  • Conteúdo gerado do lado do servidor:

Nessa imagem da mesma forma que no anterior, temos o lado do cliente/C e o lado do servidor/S, e teremos uma requisição e uma resposta para essa requisição. E essa requisição e essa resposta vai depender do tipo de conteúdo que vamos gerar, o que reflete no tipo de pre-rendering:

image

Vamos trabalhar na primeira opção que é Geração de Conteúdo Estática/Static Generation, que inclusive é a recomendada... Nesse cenário, durante o momento que rodarmos o comando npm run build ele vai gerar a aplicação para produção, e ele vai informar que aconteceu um Warning e dentro de Navegador.jsx temos que passar a referência passHref que ele vai passar isso para dentro de um link, colocando essa propriedade ele já não vai mais gerar a advertência e dessa forma vamos gerar novamente o build com o comando npm run build e nesse modendo que ele está gerando o build é que ele vai gerar o conteúdo estático, e básicamente o que ele vai gerar é um arquivo HTML e esse conteúdo será servido de forma estática e será reusado a cada requisição. Basicamente o que acontece, é que do lado do servidor foi gerado uma página HTML de forma estática e sempre que o cliente fizer uma requisição ele vai devolver esse arquivo pronto. Nesse cenário estamos trabalhando com aplicação SSG(Static Site Generator/ Geração de Site Estático):

image

CRUD usando o Next.js