-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c8cb435
commit c715e36
Showing
8 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
apps/next-intermediario/src/content/docs/04a-use-transition/01-use-transition.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
title: useTransition e startTransition | ||
--- | ||
|
||
Agora que temos nosso estado na URL, uma coisa interessante que podemos fazer é um indicador de loading no campo de busca para um feedback visual de que os dados estão sendo buscados. | ||
|
||
Um bom candidato para isso é usar o par `useTransition / startTransition`. Mas antes vamos entender rapidamente o que são eles. | ||
|
||
## O hook `useTransition()` | ||
|
||
O Hook `useTransition` nos retorna uma variável e uma função `startTransition`: | ||
|
||
```typescript | ||
const [isPending, startTransition] = useTransition() | ||
``` | ||
|
||
o `isPending` é uma variável que indica se uma transição está em andamento. Você pode usar para mostrar um indicador de *loading*. | ||
|
||
A função `startTransition` serve para "envelopar" uma função que faz alguma alteração no estado da aplicação. Quando fazemos isso estamos dizendo que aquela alteração é uma transição e não uma atualização imediata - ou seja, ela não é urgente. | ||
|
||
Isso é importante porque faz com que essa atualização de estado não bloqueie a interface do usuário. | ||
|
||
## Três casos de uso | ||
|
||
1. Evitar que uma atualização de estado bloqueie a interface do usuário. | ||
2. Atualizações otimistas (*optimistic ui*). | ||
3. Indicação de loading - por exemplo em um input de busca. | ||
|
||
## Onde não faz sentido usar? | ||
|
||
- Não faz sentido usar `startTransition` em *server components*. | ||
- Não faz sentido usar `startTransition` quando você não está lidando com uma atualização de estado. | ||
- Não faz sentido usar `startTransition` quando as atualizações são criticas e devem ser feitas imediatamente. | ||
|
||
A regra básica é que `startTransition` serve para atualizações não urgentes e que podem ser adiadas ou interrompidas. |
78 changes: 78 additions & 0 deletions
78
...termediario/src/content/docs/04a-use-transition/02-use-transition-na-pratica.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
--- | ||
title: useTransition na prática | ||
--- | ||
|
||
Entendemos razoavelmente o papel de `useTransition` e `startTransition`. Agora está na hora de usar isso na prática no nosso projeto. | ||
|
||
## Exercício - Loading no input de busca | ||
|
||
Vamos adicionar um indicador de loading no nosso input de busca. Quando a busca está em andamento vamos mostrar um *spinner* ao invés do ícone de lupa. | ||
|
||
O carregamento deve durar enquanto buscamos os dados. E deve ser interrompido | ||
|
||
:::tip | ||
use a animação spin do tailwind para mostrar o loading. | ||
::: | ||
|
||
### Solução | ||
|
||
- Primeiro, vamos chamar o hook `useTransition` no componente `SearchInput`. | ||
- Depois vamos desconstruir o `startTransition` e o `isPending` em variáveis. | ||
- Vamos usar o `isPending` para mostrar o *spinner* quando a busca está em andamento. | ||
- Vamos usar o `startTransition` para envelopar a função que busca os dados. | ||
|
||
#### Código | ||
|
||
```tsx ins={26,28,6,12,40-44} | ||
// src/app/vagas/_components/search-bar.tsx | ||
"use client"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Loader2, Search } from "lucide-react"; | ||
import { useRouter, useSearchParams } from "next/navigation"; | ||
import { useTransition } from "react"; | ||
import { useDebouncedCallback } from "use-debounce"; | ||
|
||
export default function SearchBar() { | ||
const searchParams = useSearchParams(); | ||
const previousSearchText = searchParams?.get("search") || ""; | ||
const [isPending, startTransition] = useTransition(); | ||
const router = useRouter(); | ||
|
||
const handleChange = useDebouncedCallback( | ||
(event: React.ChangeEvent<HTMLInputElement>) => { | ||
const urlSearchParams = new URLSearchParams(searchParams ?? undefined); | ||
const searchText = event.target.value; | ||
|
||
if (searchText) { | ||
urlSearchParams.set("search", searchText); | ||
} else { | ||
urlSearchParams.delete("search"); | ||
} | ||
|
||
startTransition(() => { | ||
router.replace("?" + urlSearchParams.toString()); | ||
}); | ||
}, | ||
500, | ||
); | ||
|
||
return ( | ||
<div className="mb-8"> | ||
<Input | ||
type="search" | ||
placeholder="Busque uma vaga..." | ||
className="py-6 text-lg" | ||
icon={ | ||
isPending ? ( | ||
<Loader2 className="size-4 animate-spin" /> | ||
) : ( | ||
<Search className="size-4" /> | ||
) | ||
} | ||
onChange={handleChange} | ||
defaultValue={previousSearchText} | ||
/> | ||
</div> | ||
); | ||
} | ||
``` |
84 changes: 84 additions & 0 deletions
84
apps/next-intermediario/src/content/docs/05-rotas-api/01-rotas-api-no-next.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--- | ||
title: Rotas API no Next.js | ||
--- | ||
|
||
## Rotas API no Next.js | ||
|
||
O Next.js foi inovador quando foi lançado justamente por lançar mão dos benefícios de uma aplicação que rodava em um servidor. | ||
|
||
Ao contrário do tradicional SPA React, uma aplicação Next.js está rodando em um servidor e possui acesso, portanto, ao ambiente *node* do servidor. | ||
|
||
Um dos benefícios foi poder transformar o *framework frontend* em um *framework fullstack*. E muito disso foi possível porque o Next.js implementou as chamadas **Rotas API**. | ||
|
||
Com o Next.js v13+, as Rotas APIs foram renomeadas para `Route Handlers`. | ||
|
||
## Anatomia das Route Handlers | ||
|
||
### O Arquivo | ||
|
||
Uma rota API é definida da mesma forma que uma página `page`. Exceto que o nome agora deverá ser `route.ts` ou `route.js`. | ||
|
||
:::caution | ||
Perceba que as rotas API são processadas inteiramente no servidor - dessa forma não aceitam `JSX`, e portanto a extensão não pode ser `jsx|tsx`. | ||
::: | ||
|
||
### A função | ||
|
||
Sabemos que elas são definidas dentro de um `route.ts`. Certo, mas o que é definido nesse arquivo? | ||
|
||
Necessariamente em uma rota API você deverá exportar uma (ou mais de uma) das seguintes funções assíncronas: | ||
|
||
- GET | ||
- HEAD | ||
- POST | ||
- PUT | ||
- DELETE | ||
- PATCH | ||
- OPTIONS | ||
|
||
Como não é difícil perceber, cada uma dessas funções exportadas se referirá a um método HTTP. | ||
|
||
Exemplo abaixo: | ||
|
||
```typescript | ||
export async function GET() {} | ||
|
||
export async function HEAD() {} | ||
|
||
export async function POST() {} | ||
|
||
export async function PUT() {} | ||
|
||
export async function DELETE() {} | ||
|
||
export async function PATCH() {} | ||
|
||
``` | ||
|
||
### Os parâmetros | ||
|
||
Cada uma dessas funções exportadas receberá dois parâmetros opcionais: | ||
|
||
- `request`: um objeto do tipo `Request` | ||
- `context`: um objeto do tipo `NextRequest` | ||
|
||
#### O parâmetro `request` | ||
|
||
O parâmetro `request` é um objeto do tipo `Request` que representa a requisição HTTP. O mais legal é que é um Web API Request. | ||
|
||
Isso significa que você pode usar todos os métodos disponíveis no `Request` do browser. | ||
|
||
Por exemplo, você pode acessar os parâmetros da requisição através do `searchParams`: | ||
|
||
```typescript | ||
export async function GET(request: Request) { | ||
const { searchParams } = new URL(request.url) | ||
const name = searchParams.get('name') | ||
|
||
return new Response(`Hello ${name}`) | ||
} | ||
``` | ||
|
||
#### O parâmetro `context` | ||
|
||
O parâmetro `context` é um objeto que possui uma prop `params`, que é uma promise que resolve em um objeto que contém os parâmetros da rota. |
12 changes: 12 additions & 0 deletions
12
apps/next-intermediario/src/content/docs/05-rotas-api/02-ainda-faz-sentido.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
title: Ainda faz sentido usar rotas API no Next.js? | ||
--- | ||
|
||
Sendo direto ao ponto: depois que surgiram as Server Actions / Server Functions, *não faz mas tanto sentido utilizar rotas de API*. Isso porque elas eram especialmente úteis para acessar dados do servidor diretamente de componentes frontend. Agora que componentes de cliente podem acessar *server actions* e *server functions*, não há mais necessidade de se utilizar rotas de API para isso. | ||
|
||
Aliás, *é muito mais fácil* usar uma `server action` do que uma rota de API para isso. | ||
|
||
Claro que ainda existem alguns casos de uso: | ||
|
||
1. Quando você precisa de uma rota que não é uma rota de página. Esse caso de uso pode ser útil quando você precisa acessar apenas os dados do servidor. | ||
2. Aplicações mobile, onde você precisa fazer requisições HTTP para o backend. |
47 changes: 47 additions & 0 deletions
47
...c/content/docs/06-server-actions-avancado/01-server-actions-server-functions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
title: Server Actions ou Server Functions? | ||
--- | ||
|
||
## Server Actions ou Server Functions? | ||
|
||
Até Setembro de 2024, não havia distinção entre **Server Actions** e **Server Functions**. Ambos eram chamados de **Server Actions**. | ||
|
||
A partir dessa data criou-se a distinção entre os dois. | ||
|
||
 | ||
|
||
## Server Functions | ||
|
||
### Definição de Server Function | ||
|
||
Uma **server function** é: | ||
|
||
- uma função assíncrona | ||
- definida pela diretiva `use server` | ||
- definida no lado do servidor | ||
- inline em um server component com a diretiva `use server` no início da função | ||
- em um arquivo separado com a diretiva `use server` no topo do arquivo | ||
- que pode ser utilizada tanto em *client components* quanto em *server components* | ||
|
||
### Chamando uma Server Function | ||
|
||
Uma server function pode ser chamada no cliente ou no servidor. Mas não faz muito sentido chamá-la no servidor, já que no servidor você pode usar a lógica diretamente no componente sem precisar de uma função separada. | ||
|
||
#### Chamando no Cliente | ||
|
||
Você pode invocar uma Server Function: | ||
|
||
- em um formulário (ela receberá o objeto `formData` como argumento) | ||
- em um event handler. | ||
|
||
## Server Action | ||
|
||
### Definição de Server Action | ||
|
||
Uma **server action** é: | ||
|
||
- uma **Server Function** | ||
- que é chamada diretamente em um `form` ou; | ||
- chamada dentro de uma `action` de um `form` | ||
|
||
Quando a server action é chamada em um `form`, ela recebe o objeto `formData` como primeiro argumento. |
12 changes: 12 additions & 0 deletions
12
...rio/src/content/docs/06-server-actions-avancado/02-server-functions-avancado.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
title: Server Functions - Outros tópicos | ||
--- | ||
|
||
## Invocando Server Functions dentro e fora de um formulário | ||
|
||
Quando uma Server Function é chamada em um formulário algumas coisas "mágicas" acontecem: | ||
|
||
1. Um objeto `formData` é passado como primeiro argumento (assinatura muda) | ||
2. A função é automaticamente envelopada em um | ||
|
||
### Passando argumentos para uma Server Function |
Binary file added
BIN
+160 KB
apps/next-intermediario/src/content/docs/06-server-actions-avancado/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.