diff --git a/react-nextjs-workshop/presentation.md b/react-nextjs-workshop/presentation.md index f78bdca..454b418 100644 --- a/react-nextjs-workshop/presentation.md +++ b/react-nextjs-workshop/presentation.md @@ -1,8 +1,10 @@ +

Edit in Eraser

+ class: center, middle, inverse, small-images # React ## After you learn it, there is no way back -![](./img/ni_logo.png) +![](./img/ni_logo.png "") --- @@ -86,7 +88,6 @@ function App() { ### Por exemplo - `onclick` fica `onClick` .flex-columns-center[ - ```html
@@ -129,9 +129,8 @@ function PersonDisplay({ --- # Mais um pormenor sobre props -- Por default, existe um argumento chamado `children` , que é automaticamente preenchido pelo React. +- Por default, existe um argumento chamado `children` , que é automaticamente preenchido pelo React. .flex-columns[ - ```js function Box({ children }) { return
@@ -158,7 +157,7 @@ function PersonDisplay({ # Quando é que os componentes são renderizados? - Quando a página é carregada. -- Quando uma variável de estado (com `useState` ) é atualizada. +- Quando uma variável de estado (com `useState` ) é atualizada. - Quando um pai é re-renderizado. ```js function App() { @@ -173,7 +172,6 @@ function App() { # Renderização de componentes - Nota adicional - Isto **não** funciona! O componente não vai ser re-renderizado e por isso o texto do `

` não vai ser alterado. O `useState` contém código que força a re-renderização do componente. .flex-columns-center[ - ```js function Counter() => { const counter = 0; @@ -193,7 +191,7 @@ function Counter() => { # Nota sobre funcionamento de browsers .flex-columns-center[ -![](./img/browser-workings.png) +![](./img/browser-workings.png "") ] @@ -203,7 +201,6 @@ function Counter() => { - Os browsers constroem uma àrvore chamada **DOM** (Document Object Model) que representa as relações hierárquicas dos elementos. .flex-columns[ - ```html @@ -229,7 +226,6 @@ dos elementos. # Keys - Em vez de re-renderizar a lista toda quando ela muda, com as `keys` , o react permite identificar cada elemento individualmente. .flex-columns-center[ - ```javascript function App() { const requests = fetchRequests(); @@ -250,9 +246,8 @@ function App() { # Hooks - O que são? - **Hooks** são **funções especiais** que são alocadas na memória RAM num local onde quando -retornam um valor continuam em memória com todas as variáveis dentro dela intactas. **Começam sempre com um **`**use[A-Z]**` . +retornam um valor continuam em memória com todas as variáveis dentro dela intactas. **Começam sempre com um **`**use[A-Z]**` . .flex-columns[ - ```js function counter() { const counter = 10; @@ -272,7 +267,7 @@ useCounter(); --- # Mas para o que é que isto seria útil? -- Lembram-se do `useState()` ? +- Lembram-se do `useState()` ? ```js import { useState } from 'react'; function Counter() { @@ -294,7 +289,7 @@ function Counter() { circunstâncias onde muitos componentes precisam de aceder a uma mesma variável. - Se por exemplo se tivessemos um componente `Account` que dentro dele tinha um `Profile` e dentro dele tinha um `UserBasicInfo` a renderizar informações sobre o utilizador (nome, email, etc). -- Para `Account` , `Profile` e `UserBasicInfo` terem acesso ao utilizador, neste caso, teríamos de passar o estado da seguinte forma: `Account` -> `Profile` -> `UserBasicInfo` . +- Para `Account` , `Profile` e `UserBasicInfo` terem acesso ao utilizador, neste caso, teríamos de passar o estado da seguinte forma: `Account` -> `Profile` -> `UserBasicInfo` . --- # useContext - Motivação (2/2) @@ -397,21 +392,20 @@ function Counter() { ``` ```js function useLocalStorage(storageItem, defaultValue) { - const [value, setValue] = useState(localStorage.getItem("counter") ?? 0); +const [value, setValue] = useState(localStorage.getItem("counter") ?? 0); - useEffect(() => { - localStorage.setItem("counter", value); - }, [value]); - - return [value, setValue]; +useEffect(() => { + localStorage.setItem("counter", value); +}, [value]); +return [value, setValue]; ``` --- # NextJS -Se não sabes React, não devias estar aqui... +Se não sabes React, nem devias estar aqui... -Este é um workshop de Nextjs versão 13 para cima! +Este é um workshop de Next.js **versão 13** para cima! --- @@ -419,19 +413,13 @@ Nextjs é uma **framework**. É uma tecnologia que fornece uma estrutura para o desenvolvimento de websites com bastantes benificios como **SSR** - Server Side Rendering. -Mas não só, até é possível criar uma simples Rest API sem necessidade de envolver frontend. - -NextJS é construido em cima de React e utiliza as suas funções para mexer com tudo o que é relacionadao a visualização de conteudo. - +Mas não só, até é possível criar uma simples Rest API sem necessidade de envolver _frontend_. +Next.js é construido em cima de React e utiliza as suas funções para mexer com tudo o que é relacionado com a visualização de conteúdo. --- - - -(Imagem para mostrar a cena global e onde encaixa o react e next, a que já existe no outro workshop) - - +(n1) --- @@ -441,140 +429,317 @@ O conteudo é renderizado no servidor no momento em que o utilizador faz o _requ ### Vantagens - É muito fácil fornecer **informação personalizada** com base no utilizador, como por exemplo dashboards e perfil. - Acesso a informações do _request_ como _Cookies_ e _URL Search Params_ no momento. -- Websites mais rápidos pois as páginas podem ser guardadas em **_cache_** e globalmente distribuidas. +- Websites mais rápidos pois as páginas podem ser guardadas em _**cache**_ e globalmente distribuidas. - O **Server Load é reduzido** dado que o conteudo é guardado em cache e não necessita de ser gerado novamente caso as informações não sejam modificadas. - **SEO** - Os crawlers indexam muito melhor os websites que carregam a informação no momento em que a página acontece. Isto leva a melhores rankings de pesquisa. +--- + +# Estrutura de Ficheiros +## Routing - App Router +Esta é uma das grandes mudanças na versão 13. + +> Tenham sempre cuidado a ver a documentação e se estão a ver a versão correta + +(n2) +`.ts = .js + TypeScript ` + +`.tsx = .jsx + TypeScript` --- -# Estrutura de Ficheiros ## Routing - App Router -Esta é uma das grande mudanças na versão 13. +- page.tsx e _nesting_ de folders +- layout.tsx +(n4) -> Tenham sempre cuidado a ver a documentação e se estão a ver a versão correta +> Um dos benefícios de usar layout é que ao mudar de página, os componentes do layout não voltam a ser renderizados. -![Screenshot 2024-10-20 at 10.19.13.png](/.eraser/B7xLmMUdQ2FRxOmRFJsp___kOVinmzsnGWDFGKVC6pjNOZQvzm1___UkglmhBhclLKjM8jUItM7.png "Screenshot 2024-10-20 at 10.19.13.png") +- loading.jsx +- not-found.jsx +- error.jsx +--- +## Routing - App Router +### Dynamic Routing +(n5) +``` +export default function Page({ params }: { params: { slug: string } }) { + return

My Post: {params.slug}
+} +``` +--- +## Routing - App Router +### APIs +(n6) +`request` e `context` são opcionais -.ts = .js + TypeScript +``` +export async function GET(request: Request) {} -.tsx = .jsx + TypeScript +export async function HEAD(request: Request, context: { params: Params }) {} + +export async function POST(request: Request) { + return NextResponse.json({ error: 'ISE' }, { status: 500 }) +} +export async function PUT(request: Request) {} + +export async function DELETE(request: Request) {} + +export async function PATCH(request: Request) {} + +// If `OPTIONS` is not defined, Next.js will automatically implement `OPTIONS` and set the appropriate Response `Allow` header depending on the other methods defined in the route handler. +export async function OPTIONS(request: Request) {} +``` +> Não pode existir `layout.tsx` nem `page.tsx` ao mesmo nível do route.ts. Tipicamente cria-se uma pasta `api` para servir a API. +--- -(page.tsx e nested folders e layout.tsx) +## Routing - App Router +### Other Project Organization Features +- Pastas privadas, a começar com `_`. Estas pastas não serão consideradas no _routing_ da app. +- Route groups, nome da pasta entre `()`. Desta forma é possível organizar pastas sem interferir no _routing_ da app. +--- -(loading.jsx e not-found.jsx e error.jsx) Mencionar que o RootLayout não apanha erros e que uma solução +## Metadata +`page.tsx` -(Dynamic Routing params [id]) +``` +export const metadata: Metadata = { + title: 'Título super interessante', + description: 'Os oradores são mesmo nice' +}; +``` +Dynamic Metadata -(route.ts e a maneira como se define apis) Não podem existir layout.tsx nem page.tsx no mesmo nível. Normalmente cria-se uma página separada simplesmente para esta função. +``` +export async function generateMetadata( + { params }: { params: { id: string } } +): Promise { + + const id = params.id // read route params + + const product = await fetch(`https://.../${id}`).then((res) => res.json()) + + return { + title: product.title, + openGraph: { + images: ['/some-specific-page-image.jpg'], + }, + } +} +``` +--- -Project Organization Features +## +``` +import Link from 'next/link' +``` +``` +Dashboard +``` +> Nunca usem tags `` em Next.js! -Project files can be safely colocated inside route segments in the app directory without accidentally being routable. +--- -Private folders _name +## +``` +import Image from 'next/image' +``` +``` +Picture of the author +``` +Uma das razões dos _websites_ de tornarem lentos ao carregar, é exatamente o carregamento das imagens. -Route Groups (name) +Vantagens: +- Prevenir _layout shift_ durante o carregamento de imagens. +- Redimensionamento automático para evitar enviar imagens grandes para dispositivos pequenos. +- _Lazy loading_ por definição. As imagens vão sendo carregadas à medida que vão a aparecer na janela de visualização. +- Formatos modernos, como [WebP](https://developer.mozilla.org/pt-BR/docs/Web/Media/Formats/Image_types#webp) e [AVIF](https://developer.mozilla.org/pt-BR/docs/Web/Media/Formats/Image_types#avif_image), quando o _browser_ é compatível. +--- +## "use server" vs "use client" +Por definição, todas as páginas são "use server", exceto escrito o contrário. + +O **"use client"** significa que página será renderizada do lado do cliente. Isto significa que um bundle de JavaScript será enviado para o cliente e serão possíveis usar os _hooks_ do React, tal como _useState_ e _useEffect._ + +Importar referir que o "use client" não precisa de ser especificado para uma página inteira. Podemos ter uma página 80% gerada no servidor onde apenas um componente será renderizado no cliente. + +A partir do momento que usamos **"use client"** num componente, não podemos voltar a usar **"use server"** nos seus filhos. Faz sentido, certo? --- -# Estrutura de Ficheiros -## Layouts -Um beníficio de usar layouts é o facto de que ao mudar de página, os componentes do layout não voltam a ser renderizados. +****## "use server" vs "use client" +(n7) +--- +## Server Actions +- Funções assíncronas +- Rodam no servidor +- Podem ser chamadas no lado do cliente. +``` +'use server' + +export async function updateItem(itemId, formData) { + // database stuff here +} +``` +``` +'use client' -(layout.tsx) +import { updateItem } from './actions' + +export default function ClientComponent({itemId}) { + return
{/* ... */}
+} +``` +Como enviar o `itemId` para o `updateItem`? + +--- +## Server Actions - [Pending states](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#pending-states) --- -## Metadata -() +## Filosofia da framework! +"We recommend first attempting to **fetch data on the server-side**." + +- "However, there are still cases where client-side data fetching makes sense. In these scenarios, you can manually call `fetch` in a `useEffect` (not recommended), or lean on popular React libraries in the community such as [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest) ." +"To reduce the Client JavaScript bundle size, we recommend moving **Client Components down your component tree**." + +"Optimizations, whenever is possible" --- -## -(import ....) +## Coisas interessantes para explorar em casa +- Middleware +- ORM (Prisma or Drizzle) +- Parallel Routes & Tab Groups +- Interception Routes +- Internationalization +- React [useOptimistic](https://react.dev/reference/react/useOptimistic) +- NextAuth +--- + +# Bora ao trabalho! +> Mini site para inserir links de recursos interessantes da L.EIC. + -Mudar de página nunca soube tão bem. +Requisitos: + +- [Node.js](https://nodejs.org/en) acima da versão 18 +Primeiros passos: + +- `git clone <>` +- `cp .env.example .env` + - Mudar o `` + - Mudar a `` +- `npm install` +- `npx prisma generate` --- -## -(import ....) +## Tarefa #1  - Primeiro Componente em React +`app/components/feed-resource-card.tsx` -Imagens sempre automatizadas. +Implementa o componente `ResourceCard` . -Uma das razões dos websites de tornarem lentos ao carregar, é exatamente o loading das imagems. +Tens um html para te ajudar! -(dados / estudo aqui?) +--- -Beníficios de usar: +## Tarefa #2 - Listar os recursos no feed +`app/@feed/page.tsx` + +- Se não existirem recursos, mostrar uma mensagem a dizer "No resources found", exemplo: +``` +
+ No resources found. +
+``` +- Se existirem recursos, mostrar uma lista de ResourceCard. +> Não te esqueças do `key` -- Prevenir _layout shift_ durante o carregamento de imagens. -- Redimensionamento automatico para evitar enviar imagens grandes para dispositivos pequenos. -- _Lazy loading_ por definição. As imagens vão sendo carregadas à medida que vão aparecendo na janela de visualização. -- Formatos modernos, como [WebP](https://developer.mozilla.org/pt-BR/docs/Web/Media/Formats/Image_types#webp) e [AVIF](https://developer.mozilla.org/pt-BR/docs/Web/Media/Formats/Image_types#avif_image) , quando o _browser_ é compatível. --- -## "use server" vs "use client" -Por definição, todas as páginas são "use server", exceto escrito o contrário. +## Tarefa #3 - Adptar a página de um recurso +`app/resources/[id]/page.tsx` -O "use client" significa que página será renderizada do lado do cliente. Isto é muito bom para podermos fazer uso dos _hooks_ do React, como _useState_ e _useEffect._ +Consoante o recurso selecionado através do url, adapta a página para mostrar informações relevantes desse recurso. -Mas o "use client" não precisa de ser especificado para um página inteira. Podemos ter uma página 80% gerada no servidor onde apenas um componente será definido para ser renderizado na parte do cliente. +- Deves começar por pegar no `id` do recurso do url +- Usar o `id` para ir buscar o recurso à base de dados. +- Se o recurso não existir, podes mostrar uma página de erro 404. +- Se o recurso não tiver `thumbnail`, usa a imagem que existe em `/public/images/placeholder.jpg`. -A partir do momento que usamos "use client" num componente, não podemos voltar a usar "use server" nos seus filhos. Faz sentido, certo? +Bónus: +- Cria uma função para copiar o url da página ao clicar no botão share. -(imagem de tree rendering) +--- +## Tarefa #4 - Escreve o Metadata da página do recurso +`app/resources/[id]/page.tsx` -**When to use Server and Client Components?** +Inspeciona o _website_ e verifica dentro do `` se o título e a descrição estão a ser preenchidos. -![Screenshot 2024-10-20 at 11.32.22.png](/.eraser/B7xLmMUdQ2FRxOmRFJsp___kOVinmzsnGWDFGKVC6pjNOZQvzm1___U2r09-IdJ0g2KtjGgtOU_.png "Screenshot 2024-10-20 at 11.32.22.png") +> Dica: Consulta os slides à procura do generateMetadata. --- -## Server Actions -(...) +## Tarefa #5 - Criar uma página 404 para um recurso não encontrado +Qual é o ficheiro que deves criar e onde deves colocar? --- -## Filosofia atual da framework -"We recommend first attempting to **fetch data on the server-side**." +## Tarefa #6 - Escreve o Metadata da página do recurso +`app/resources/[id]/counter.tsx` -- However, there are still cases where client-side data fetching makes sense. In these scenarios, you can manually call `fetch` in a `useEffect` (not recommended), or lean on popular React libraries in the community such as [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest). -"To reduce the Client JavaScript bundle size, we recommend moving Client Components down your component tree." +(n8) +- O contador deve ser incrementado sempre que o botão for clicado +- Mostra o número de reações +- (Bonus) Guarda o número de reações no localStorage e acessa o valor guardado ao carregar a página --- -## Mais cenas interessantes que podem explorar em casa -- Middleware -- ORM (Prisma or Drizzle) -- Parallel Routes & Tab Groups -- Interception Routes -- Internationalization -- React [useOptimistic](https://react.dev/reference/react/useOptimistic) -- NextAuth +## Tarefa #7 - Completa a Server Action para adicionar um recurso novo +`lib/actions/resources.ts` + +Acaba de implementar a Server Action que adiciona um recurso novo! + +A função recebe um campo "url" a partir de um FormData. + +- Deves ver se o recurso já existe e se sim, retornar um erro +- Obter informação do recurso submetido a partir do URL. +> Dica: Ver as funções importadas + +- Criar o recurso na base de dados. +> Dica: Ver class `Database` + +- Revalidar o cache da página inicial --- -Bora ao trabalho! +# É tudo por hoje! +Obrigado + + + + -() + \ No newline at end of file