From e2c2e70e195db4ce645666640b28b04c59eded52 Mon Sep 17 00:00:00 2001 From: Daniel Heras Quesada Date: Wed, 17 Jan 2024 09:25:35 +0100 Subject: [PATCH] V1 presentation styling + API data fetching --- presentation/src/app/api/wordlist/route.tsx | 13 +++ presentation/src/app/presentation/page.tsx | 87 ++++++------------- .../components/apiside-word-list.tsx | 33 +++++++ .../components/clientside-word-list.tsx | 2 +- .../components/revalidate-button.tsx | 4 +- presentation/src/app/word-list/page.tsx | 2 + presentation/src/app/word-list/utils.ts | 6 +- presentation/src/styles/main.css | 42 +++++++-- 8 files changed, 119 insertions(+), 70 deletions(-) create mode 100644 presentation/src/app/api/wordlist/route.tsx create mode 100644 presentation/src/app/word-list/components/apiside-word-list.tsx diff --git a/presentation/src/app/api/wordlist/route.tsx b/presentation/src/app/api/wordlist/route.tsx new file mode 100644 index 0000000..55dc8cc --- /dev/null +++ b/presentation/src/app/api/wordlist/route.tsx @@ -0,0 +1,13 @@ +import { NextResponse } from 'next/server' +import { fetchWordlist } from 'src/app/word-list/utils' + +export async function GET(request: Request) { + // const { searchParams } = new URL(request.url) + // const url = searchParams.get('url') + // console.log(url) + + const res = await fetchWordlist() + + console.log('API Data fetch is done', res) + return NextResponse.json(res) +} diff --git a/presentation/src/app/presentation/page.tsx b/presentation/src/app/presentation/page.tsx index 6c362e2..dfbd798 100644 --- a/presentation/src/app/presentation/page.tsx +++ b/presentation/src/app/presentation/page.tsx @@ -37,10 +37,9 @@ export default function Presentation() { function Introduction() { return (
-

Next

-
-

Nos da la posibilidad de renderizar desde el servidor

-
+

+ NEXT.JS +

) } @@ -50,17 +49,21 @@ function Rendering() {

Rendering

- The rendering works is split into chunks: - By individual route - segments - By React [Suspense - boundaries](https://react.dev/reference/react/Suspense) (react - way of having a fallback while a components has finished - loading) Each chunk is rendered in the server, then, on the - client: 1. The HTML is used to immediately show fast preview. 2. - The server components rendered are inserted to update the DOM - (components rendered in server with placeholders for client - components and props). 3. `JS` instructions are used to - [hydrate?](https://react.dev/reference/react-dom/client/hydrateRoot) - Client Components and make the application interactive. + The rendering works is split into chunks: +
    +
  • - By individual route segments
  • +
  • - By React with Suspense boundaries
  • +
+ Each chunk is rendered in the server, then, on the client: +
    +
  • + 1. The HTML is used to immediately show fast preview +
  • +
  • 2. The components are inserted to update the DOM
  • +
  • + 3. JS instructions are used to hydrate client components +
  • +
) @@ -72,25 +75,9 @@ function Strategies() {

Strategies

@@ -100,33 +87,15 @@ function Strategies() { function Benefits() { return (
-

Beneficios

+

Benefits

    -
  • - - Fetch data directly on the server, performance and - load benefits. -
  • -
  • - - Security: sensitive data is kept int the server (API - keys and tokens) -
  • -
  • - - Caching: results can be cached to improve performance - between users. -
  • -
  • - - Bundle size: will be reduced as part of the - application will reside in the server. -
  • -
  • - - SEO: because the pages will be rendered the search - engine bots will make good use of it. -
  • -
  • - - Streaming: to split the rendering into chunks and - stream them as they become ready. -
  • +
  • - Fetch data directly on the server
  • +
  • - Security: sensitive data is kept int the server
  • +
  • - Caching
  • +
  • - Bundle size reduced
  • +
  • - SEO
  • +
  • - Streaming
diff --git a/presentation/src/app/word-list/components/apiside-word-list.tsx b/presentation/src/app/word-list/components/apiside-word-list.tsx new file mode 100644 index 0000000..a809a33 --- /dev/null +++ b/presentation/src/app/word-list/components/apiside-word-list.tsx @@ -0,0 +1,33 @@ +'use client' + +import { useEffect, useState } from 'react' +import { WordListRepsonse, fetchWordlist } from '../utils' + +export default function NextAPIWordList() { + const [data, setData] = useState() + + const fetchData = () => + fetchWordlist('http://localhost:3001/api/wordlist').then((response) => + setData(response) + ) + + useEffect(() => { + fetchData() + }, []) + + return ( +
+

+ Wordlist fetched in the API +

+
+ {data?.wordList.map((word) => ( + {word.word} + ))} +
+
+ +
+
+ ) +} diff --git a/presentation/src/app/word-list/components/clientside-word-list.tsx b/presentation/src/app/word-list/components/clientside-word-list.tsx index 20c7cb6..53dd91f 100644 --- a/presentation/src/app/word-list/components/clientside-word-list.tsx +++ b/presentation/src/app/word-list/components/clientside-word-list.tsx @@ -24,7 +24,7 @@ export default function ClientWordList() { ))}
- +
) diff --git a/presentation/src/app/word-list/components/revalidate-button.tsx b/presentation/src/app/word-list/components/revalidate-button.tsx index 657b18f..9fd3d2e 100644 --- a/presentation/src/app/word-list/components/revalidate-button.tsx +++ b/presentation/src/app/word-list/components/revalidate-button.tsx @@ -2,9 +2,9 @@ import { revalidateFetchByTag } from '../actions' -export default function RevalidateButton() { +export default function RevalidateButton(props: { tag?: string }) { return ( - ) diff --git a/presentation/src/app/word-list/page.tsx b/presentation/src/app/word-list/page.tsx index b281ebc..e066682 100644 --- a/presentation/src/app/word-list/page.tsx +++ b/presentation/src/app/word-list/page.tsx @@ -1,3 +1,4 @@ +import NextAPIWordList from './components/apiside-word-list' import ClientWordList from './components/clientside-word-list' import GoBackButton from './components/go-back-button' import ServerWordList from './components/serverside-word-list' @@ -7,6 +8,7 @@ export default function WordList() {
+
) } diff --git a/presentation/src/app/word-list/utils.ts b/presentation/src/app/word-list/utils.ts index 7564ff6..daa8d3b 100644 --- a/presentation/src/app/word-list/utils.ts +++ b/presentation/src/app/word-list/utils.ts @@ -1,5 +1,5 @@ const WORDLIST_API_URL = - 'http://localhost:3000/words/es?complexity=medium&howMany=30' + 'http://localhost:3000/words/es?complexity=medium&howMany=20' export type WordElement = { word: string @@ -11,8 +11,8 @@ export type WordListRepsonse = { } // fetch("https://...", { cache: "no-store" }); -export const fetchWordlist = async () => { - const wordList: WordListRepsonse = await fetch(WORDLIST_API_URL, { +export const fetchWordlist = async (url?: string) => { + const wordList: WordListRepsonse = await fetch(url ?? WORDLIST_API_URL, { next: { tags: ['wordlist'] }, }).then((response) => response.json()) diff --git a/presentation/src/styles/main.css b/presentation/src/styles/main.css index 4c32264..3ee6fec 100644 --- a/presentation/src/styles/main.css +++ b/presentation/src/styles/main.css @@ -6,16 +6,18 @@ .data-fetching { display: grid; - padding: 20rem; - gap: 8rem; + padding: 0 10rem; + gap: 5rem; background-color: #fafafa; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr; + align-items: center; + height: 100vh; > * { background-color: #e9ecef; border-radius: 1.5rem; padding: 2rem; - min-height: 15rem; + height: 15rem; display: flex; flex-direction: column; @@ -85,10 +87,40 @@ > h3 { text-align: center; - font-size: 2.8rem; + font-size: 3rem; font-weight: 100; } + div > ul { + padding: 0 8rem; + + > li { + font-weight: 200; + font-size: 1.4rem; + margin: 10px 0; + } + } } + font-size: 1.1rem; + font-weight: 200; &-comparation { + h1 { + padding-top: 5rem; + text-align: center; + font-size: 8rem; + font-weight: 100; + + > span { + font-size: 3rem; + } + } + } + &-benefits { + div > ul { + padding: 0 15rem; + + > li { + font-size: 1.2rem; + } + } } }