Next.js: criando aplicações fullstack

Next.js: criando aplicações fullstack

O Next.js 14 é como um conjunto de ferramentas completo para quem desenvolve sites e aplicativos.

Por isso, eu diria, mantenha-o sempre à mão! Ele simplifica o trabalho, permitindo gerenciar tanto a aparência do site quanto às funcionalidades internas em um único lugar.

Não é mais necessário alternar entre diferentes ferramentas para cada tarefa. Tudo se torna mais integrado e fácil de controlar.

E veja só, esta versão é incrível! Torna os sites mais rápidos e agradáveis de usar. E o melhor de tudo: prioriza a segurança como nunca antes.

Protege os dados de visitantes e do próprio site, permitindo que você se concentre no que realmente importa, que é criar um site incrível para sua clientela.

Para as pessoas desenvolvedoras que trabalham com o back-end, o Next.js 14 é uma maravilha.

Ele não apenas torna o trabalho mais simples, mas também mais eficiente. Os sites se tornam robustos o suficiente para suportar um grande número de pessoas usuárias simultâneas e uma grande quantidade de dados, sem problemas.

Essa solidez é benéfica tanto para quem desenvolve a aplicação quanto para quem a utiliza, tornando a experiência na web mais suave e segura.

Next.js: uma plataforma fullstack completa

Como já dito, o Next.js 14 traz um conjunto de ferramentas para potencializar a criação de aplicativos.

Mas ainda o Next traz recursos adicionais, como Next.js Commerce, que é um kit pronto para e-commerce no Next.js, oferecendo uma loja online rápida, customizável e fácil de usar, com todas as funcionalidades essenciais.

Uma das coisas que facilita absurdamente a implementação de autenticação, que por vezes pode ser complicada é o Next.js Auth, que é basicamente um módulo dentro do Next.js que facilita a implementação de autenticação nas aplicações.

Ele permite que você adicione facilmente funcionalidades de login e controle de acesso, trabalhando com vários provedores de autenticação, como Google, Facebook, e até autenticação baseada em email.

Com o Next.js Auth, gerenciar sessões de pessoas usuárias, proteger rotas e manter a segurança se torna mais simples e integrado ao restante do seu projeto Next.js.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

E quais as principais facilidades que o Next.js nos traz?

As principais funcionalidades que o Next.js nos traz:

Otimizações Integradas

O Next.js 14 torna automático melhorar a experiência do usuário e a saúde do site, otimizando imagens, fontes e scripts.

Isso significa que o site carrega mais rápido e parece mais bonito sem trabalho extra.

Busca de dados

Você pode pegar os dados que precisa para o seu componente React de maneira assíncrona.

Isso significa que você pode esperar que esses dados estejam prontos, seja do servidor ou do lado do cliente, tornando tudo mais dinâmico e ágil.

Server actions

É possível executar códigos do servidor diretamente, sem a necessidade de uma API intermediária.

Isso ajuda a atualizar os dados mais rapidamente e a tornar a interface do usuário mais responsiva.

Roteamento avançado e layouts aninhados

Next.js 14 permite criar caminhos e estruturas dentro do site de maneira fácil, suportando padrões de roteamento complexos e vários layouts, ajudando a construir sites sofisticados e organizados.

Transmissão HTML dinâmica

Envia a interface do usuário do servidor para o navegador instantaneamente, trabalhando junto com o sistema de roteamento do aplicativo e a função React Suspense para uma experiência mais fluida e interativa.

Suporte a CSS

Você pode estilizar sua aplicação usando as ferramentas que mais gosta, incluindo módulos de CSS, Tailwind CSS e bibliotecas comunitárias populares, dando mais liberdade e opções para o design do site.

Manipuladores de rota

Crie pontos de conexão API para se comunicar com segurança com serviços terceirizados, o que é essencial para tarefas como autenticação e integrações.

Middleware

Controla as requisições que chegam, usando código para definir regras de roteamento e acesso, essencial para autenticação, experimentação e internacionalização, oferecendo mais controle e segurança.

React server components

Adiciona componentes ao seu site sem enviar Javascript adicional do lado do cliente, o que ajuda a manter o site leve e ágil.

Renderização do Cliente e do Servidor

Oferece opções flexíveis de renderização e cache, incluindo a Regeneração Estática Incremental (ISR), que ajuda as páginas do site a se atualizarem de forma inteligente e eficiente.

O Next.js, coloca o poder da pessoa desenvolvedora com o desenvolvimento fullstack na ponta dos dedos do desenvolvedor de front-end, simplificando o processo de construção de aplicações web completas.

Caso tenha interesse em visitar a visão geral do que está descrito acima, reserve um tempo para consultar o site oficial do Next.js aqui.

Next.js do lado do servidor

O Next.js no lado do servidor é como um ajudante nos bastidores de um site. Quando alguém visita um site, esse ajudante prepara tudo que a pessoa vai ver e usar antes mesmo de chegar ao navegador dela.

Como se fosse um cozinheiro preparando os ingredientes antes de servir o prato, o Next.js no servidor deixa as informações prontas para serem entregues rapidamente e da melhor forma ao visitante do site.

Isso torna o site mais rápido, porque muita coisa já está pronta antes mesmo de o usuário pedir, e mais seguro, pois o ajudante pode verificar as coisas nos bastidores antes de mostrá-las.

No exemplo a seguir do code-connect, isso é uma lógica do lado do servidor, especificamente uma API route no Next.js.

// src/app/api/comment/[id]/replies/route.js

import db from "../../../../../../prisma/db";

export async function GET (_request, { params }) {
    const replies = await db.comment.findMany({
        where: {
            parentId: parseInt(params.id)
        },
        include: {
            author: true
        }
    })
    return Response.json(replies)
}

Essa parte do código é como uma receita que diz ao servidor o que fazer quando alguém pede informações sobre comentários de uma determinada parte do site.

Primeiro, ele importa a conexão com o banco de dados, que é como ter todos os ingredientes à mão.

Quando a função GET é chamada, isso significa que alguém está pedindo para ver os comentários.

O servidor então vai ao banco de dados, que é como um grande arquivo, e procura todos os comentários que correspondem ao ID do pai que foi pedido.

O ID do pai ajuda a encontrar exatamente quais comentários devem ser mostrados, como se estivesse procurando por uma receita específica em um livro de receitas.

O include: { author: true } é como pedir para a receita incluir também quem fez o prato, ou seja, traz informações sobre o autor do comentário junto.

Depois que o servidor encontra todas as informações, ele usa Response.json(replies) para colocar tudo em uma bandeja bem organizada e entregar para quem pediu, ou seja, ele manda de volta uma resposta em um formato que o navegador pode entender e mostrar ao usuário.

E quem pediu isso?

Quem pediu para ver as respostas foi uma parte do código que roda no navegador do usuário, ou seja, no lado do cliente (client-side).

Este código está em um arquivo de um componente React chamado Replies.

'use client'

import { useEffect, useState } from 'react'
import styles from './replies.module.css'
import { Comment } from '../Comment'
import { ReplyModal } from '../ModalReply'

export const Replies = ({ comment }) => {

    const [showReplies, setShowReplies] = useState(false)

    const [replies, setReplies] = useState([])

    async function fetchData() {

        // aqui que fazemos o get para pegar o replies, ou seja, chama o API route acima
        const response = await fetch(`/api/comment/${comment.id}/replies`)
        const data = await response.json()
        setReplies(data)
    }

    useEffect(() => {
        if (showReplies) {
            fetchData()
        }
    }, [showReplies])

    return (<div className={styles.container}>

        <div className={styles.replies}>
            <button 
                className={styles.btn} 
                onClick={() => setShowReplies(!showReplies)}
            >
                {showReplies ? 'Ocultar' : 'Ver'} respostas
            </button>
            {showReplies && <ul>
                { replies.map(reply => <li key={reply.id}>
                    <Comment comment={reply}/>
                    <ReplyModal comment={reply}/>
                </li>) }
            </ul>}
        </div>
    </div>)
}

Bora entender o que acontece passo a passo:

  1. O componente Replies recebe um comentário como propriedade.
  2. Ele mantém um estado chamado showReplies para controlar se as respostas devem ser mostradas ou não.
  3. replies é um estado que vai armazenar a lista de respostas do comentário.
  4. A função fetchData é usada para buscar as respostas. Ela chama a API do servidor /api/comment/${comment.id}/replies, do exemplo do API route src/app/api/comment/[id]/replies/route.jspara obter as respostas relacionadas ao comentário.
  5. O useEffect é uma função especial do React que executa a fetchData sempre que o valor de showReplies muda e se for true.
  6. Quando o usuário clica no botão para ver as respostas, setShowReplies muda o estado e, como resultado, as respostas são buscadas e mostradas.

Resumindo, quando o usuário quer ver as respostas de um comentário, este código pede ao servidor para buscar essas respostas usando a rota API que vimos antes.

Assim que as respostas são recebidas, elas são mostradas na interface do site. Então quer dizer que implementar a lógica no servidor é fácil com Next.js?

Sim, é bem fácil implementar lógica no servidor com o Next.js. O framework foi feito para tornar essas tarefas simples e diretas.

Com as API routes do Next.js, você pode criar funções de servidor que lidam com todas as necessidades de back-end, como buscar dados, lidar com autenticações e muito mais.

Tudo isso sem a necessidade de configurar um servidor separado ou usar outras ferramentas de back-end.

E sobre Server Actions, onde se encaixa?

Server Actions no Next.js é uma forma de interagir com o servidor diretamente de dentro do código no lado do cliente.

Em vez de criar endpoints API tradicionais para realizar ações como buscar dados, autenticar usuários, ou manipular informações, você pode simplesmente chamar uma função.

Essas ações são executadas no servidor, o que significa que você pode fazer alterações no banco de dados ou acessar informações sensíveis sem expô-las diretamente ao cliente.

Isso simplifica o processo de implementação ao realizar interações do lado do servidor.

Você pode pensar nas Server Actions como atalhos que permitem atualizar ou buscar dados sem sair do contexto do aplicativo no lado do cliente.

Isso mantém a lógica relacionada a dados em um único lugar e reduz a quantidade de código necessária para realizar tarefas que normalmente exigiria uma API separada.

No code-connect temos um exemplo bem interessante sobre Server Actions.

Primeiro, temos a função postComment, que é uma Server Action. Ela é chamada quando alguém quer postar um novo comentário:

// Esta função é executada no servidor.
export async function postComment(post, formData) {
  // Primeiro, encontra o autor do comentário no banco de dados.
  const author = await db.user.findFirst({
    where: {
      username: "anabeatriz_dev",
    },
  });

  // Depois, cria um novo comentário com os dados recebidos do formulário.
  await db.comment.create({
    data: {
      text: formData.get("text"), // O texto do comentário.
      authorId: author.id,        // O ID do autor.
      postId: post.id,            // O ID do post onde o comentário será feito.
    },
  });

  // Atualiza a página inicial e a página do post para mostrar o novo comentário.
  revalidatePath("/");
  revalidatePath(`/${post.slug}`);
}

No componente que usa essa Server Action, o CardPost, a variável submitComments é preparado para ser usado quando o formulário do modal for enviado:

// Aqui 'post' é a postagem atual onde o comentário será feito.
const submitComment = postComment.bind(null, post);

// Este é o componente que inclui o modal e mostra a quantidade de comentários.
<div>
  <ModalComment action={submitComment}/>
  <p>
      {post.comments.length}
  </p>
</div>

E finalmente, temos o componente ModalComment, que é onde o usuário digita e envia o comentário:

// O código do componente do modal, que é uma interface para escrever e enviar comentários.
"use client";

import { useRef } from "react";

// ... outros imports ...

export const ModalComment = ({ action }) => {
  const modalRef = useRef(null);
  return (
    <>
      <Modal ref={modalRef}>
        <form 
          action={action} 
          onSubmit={() => modalRef.current.closeModal()}
        >
          <Subheading>Deixe seu comentário sobre o post:</Subheading>
          <Textarea
            required
            rows={8}
            name="text"
            placeholder="Digite aqui..."
          />
          <div className={styles.footer}>
            <SubmitButton>Comentar</SubmitButton>
          </div>
        </form>
      </Modal>
      <IconButton onClick={() => modalRef.current.showModal()}>
        <Chat />
      </IconButton>
    </>
  );
};

Quando o usuário clica para comentar, o modal aparece, ele escreve o comentário e envia. A função submitComment é chamada, processando o comentário no servidor e atualizando as páginas necessárias para mostrar o comentário recém-adicionado.

Uma grande vantagem é que desta forma, conseguimos escrever as Server Actions diretamente dentro do projeto de front-end, sem a necessidade de configurar um servidor separado ou criar um back-end tradicional.

O Next.js lida com essas requisições de forma interna, e as funções que escrevemos são executadas no servidor automaticamente quando chamadas pelo front-end.

Isso simplifica muito o processo de desenvolvimento, pois podemos nos concentrar em escrever as funcionalidades necessárias sem se preocupar com a configuração e manutenção de um servidor separado.

Tudo é gerenciado pelo próprio framework Next.js, que também cuida da segurança e da otimização dessas interações entre o cliente e o servidor.

Para maiores detalhes sobre Server Actions, eu indico fortemente a leitura deste artigo que inclusive é um passo a passo de como implementar.

Middleware

Middleware no Next.js é como um segurança que verifica tudo antes de uma pessoa entrar numa festa.

Ele pode decidir se alguém pode entrar, para onde essa pessoa vai dentro da festa, ou mesmo dar um aviso que diz o que ela pode fazer lá dentro.

Quando criamos um Middleware no Next.js, estamos dizendo ao servidor para rodar um pedaço de código antes de terminar de responder a um pedido que veio do navegador de alguém.

Assim, podemos redirecionar alguém para outra página, mudar o caminho que o navegador pediu inicialmente, ou até mesmo adicionar informações extras nos cabeçalhos da resposta que vai ser enviada de volta.

Por exemplo, podemos usar Middleware para:

  • Autenticação: checar se o visitante tem permissão para acessar certas páginas ou funcionalidades.
  • Redirecionamentos: mudar o caminho do visitante automaticamente com base em certas condições, tipo de onde ele está vindo ou se ele já visitou antes.
  • Rewriting: mudar o endereço interno que o servidor vai usar para responder ao pedido sem o visitante perceber.
  • Detecção de bots: identificar e bloquear robôs que tentam acessar o site para fazer coisas ruins.
  • Logs e Análises: gravar o que os visitantes estão fazendo para entender melhor como eles usam o site.
  • Feature flags: ligar ou desligar certas funcionalidades do site para diferentes pessoas, facilitando testes de novas ideias.

Podemos colocar o código do Middleware em um arquivo chamado middleware.js (ou .ts se estiver usando TypeScript) na raiz do seu projeto.

E você pode usar algo chamado "matcher" para dizer exatamente em quais páginas ou caminhos esse código deve ser executado.

Vamos ver um exemplo:

// Este é um Middleware que redireciona todas as visitas para /about para a página /home.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.redirect(new URL('/home', request.url))
  }
}

export const config = {
  matcher: '/about/:path*',
}

Esse código anterior verifica se o caminho da requisição começa com /about e, se sim, manda o visitante para a página /home. O matcher diz para o Middleware só olhar para os caminhos que começam com /about.

Então, basicamente, o Middleware ajuda a fazer várias coisas antes de entregar a página ou a resposta ao navegador, como um segurança que checa os convites antes de deixar as pessoas entrarem na festa.

A documentação oficial do Next.js se aprofunda mais neste assunto de Middleware, eu recomendo a leitura, pois é muito útil, veja aqui.

Conclusão

O Next.js 14, realmente transformou a forma de construir e gerenciar aplicações.

Ele é como aquele amigo multifuncional que está sempre pronto para ajudar, tanto na cozinha quanto arrumando a sala: cuida de tudo, do front-end ao back-end, com uma eficiência e simplicidade que deixam qualquer um impressionado.

A maravilhosa experiência para a pessoa desenvolvedora, está na facilidade de usar um só ambiente para gerenciar diferentes aspectos da aplicação, eliminando a necessidade de pular de uma ferramenta para outra e trazendo de graças às facilidades de lidar com o lado do servidor, segurança, etc.

E gostaria de reforçar, que fortalece com uma segurança de nível superior, garantindo que tanto os dados dos visitantes quanto os do site estejam seguros.

Para as pessoas desenvolvedoras de back-end, é um espetáculo, porque simplifica os processos, aumenta a potência e oferece robustez para lidar com altas cargas e dados volumosos.

Além disso, suas funcionalidades como Next.js Commerce e Next.js Auth são game-changers, tornando o e-commerce e a autenticação um processo quase trivial.

As otimizações integradas, facilidade na busca de dados, ações de servidor, roteamento avançado, e suporte a CSS são apenas a ponta do iceberg.

A capacidade de realizar renderizações tanto no lado do cliente quanto do servidor, é simplesmente lindo, é como ter um superpoder no desenvolvimento web.

Tudo isso, combinado com as facilidades de Middleware e Server Actions, coloca o Next.js 14 em uma categoria própria.

É uma ferramenta que não só facilita a vida de pessoas desenvolvedoras de software, mas também eleva a qualidade da experiência do usuário final.

Então, para quem está construindo o próximo grande site ou aplicação, o Next.js 14 é mais do que uma escolha — é um aliado indispensável.

Espero que tenham gostado deste overview sobre os grandes poderes deste lindo, maravilhoso, framework completo.

Se quiser se aprofundar no assunto

Aqui na Alura, temos vários conteúdos sobre Next, vamos conhecê-las?

Além disso, você vai aprender conceitos-chave da ferramenta e ver na prática como criar suas primeiras páginas usando o framework.

Nessa formação, trabalhamos com a versão 13 do Next. Nela, você aprenderá o que é e como construir um Design System usando as tecnologias mais populares de desenvolvimento web.

Aproveite e veja os conteúdos que a comunidade Next divulgou na última conferência.

Compartilhando o que você aprendeu

E vamos lançar um desafio! Se você gostou desse artigo, compartilhe nas redes sociais o que você aprendeu com ele com a hashtag #AprendinoBlogdaAlura.

Patrícia Silva
Patrícia Silva

Sou Engenheira de Software, atualmente atuando como Fullstack Engineer e baseada em Portugal. Sou uma profissional entusiasmada que ama tecnologia. Trabalho como desenvolvedora web há mais de 15 anos. Ajudo desenvolvedores a melhorar suas habilidades e estou aberta a trocas de conhecimento com qualquer pessoa. Sou mãe de plantas e de dois meninos lindos. Adoro viajar, conhecer novas pessoas e estar em contato com a natureza. O foco e o cuidado com a experiência do usuário são o segredo do sucesso.

Veja outros artigos sobre Front-end