V1 presentation styling + API data fetching

This commit is contained in:
Daniel Heras Quesada
2024-01-17 09:25:35 +01:00
parent 3869d67172
commit e2c2e70e19
8 changed files with 119 additions and 70 deletions

View File

@@ -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)
}

View File

@@ -37,10 +37,9 @@ export default function Presentation() {
function Introduction() { function Introduction() {
return ( return (
<div className="main-presentation-comparation"> <div className="main-presentation-comparation">
<h3>Next</h3> <h1>
<div> NEXT<span>.JS</span>
<p>Nos da la posibilidad de renderizar desde el servidor</p> </h1>
</div>
</div> </div>
) )
} }
@@ -50,17 +49,21 @@ function Rendering() {
<div className="main-presentation-comparation"> <div className="main-presentation-comparation">
<h3>Rendering</h3> <h3>Rendering</h3>
<div> <div>
The rendering works is split into chunks: - By individual route The rendering works is split into chunks:
segments - By React [Suspense <ul>
boundaries](https://react.dev/reference/react/Suspense) (react <li>- By individual route segments </li>
way of having a fallback while a components has finished <li>- By React with Suspense boundaries </li>
loading) Each chunk is rendered in the server, then, on the </ul>
client: 1. The HTML is used to immediately show fast preview. 2. Each chunk is rendered in the server, then, on the client:
The server components rendered are inserted to update the DOM <ul>
(components rendered in server with placeholders for client <li>
components and props). 3. `JS` instructions are used to 1. The HTML is used to immediately show fast preview
[hydrate?](https://react.dev/reference/react-dom/client/hydrateRoot) </li>
Client Components and make the application interactive. <li>2. The components are inserted to update the DOM</li>
<li>
3. JS instructions are used to hydrate client components
</li>
</ul>
</div> </div>
</div> </div>
) )
@@ -72,25 +75,9 @@ function Strategies() {
<h3>Strategies</h3> <h3>Strategies</h3>
<div> <div>
<ul> <ul>
<li> <li>- Static rendering (default)</li>
- Static rendering (default): Good for static pages: <li>- Dynamic rendering: rendered per user request</li>
Rendered in build time or in the background after data <li>- Streaming: work is split into chunks and streamed</li>
revalidation
</li>
<li>
- Security: sensitive data is kept int the server (API
keys and tokens)
</li>
<li>
- Dynamic rendering: rendered per user request, Next
uses this type of rendering automatically when discovers
a dynamic function (`cookies()`, `headers()`,
`userSearchParams()`).
</li>
<li>
- Streaming: work is split into chunks and streamed as
they become ready so the load is progressive.
</li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -100,33 +87,15 @@ function Strategies() {
function Benefits() { function Benefits() {
return ( return (
<div className="main-presentation-benefits"> <div className="main-presentation-benefits">
<h3>Beneficios</h3> <h3>Benefits</h3>
<div> <div>
<ul> <ul>
<li> <li>- Fetch data directly on the server</li>
- Fetch data directly on the server, performance and <li>- Security: sensitive data is kept int the server</li>
load benefits. <li>- Caching</li>
</li> <li>- Bundle size reduced</li>
<li> <li>- SEO </li>
- Security: sensitive data is kept int the server (API <li>- Streaming</li>
keys and tokens)
</li>
<li>
- Caching: results can be cached to improve performance
between users.
</li>
<li>
- Bundle size: will be reduced as part of the
application will reside in the server.
</li>
<li>
- SEO: because the pages will be rendered the search
engine bots will make good use of it.
</li>
<li>
- Streaming: to split the rendering into chunks and
stream them as they become ready.
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,33 @@
'use client'
import { useEffect, useState } from 'react'
import { WordListRepsonse, fetchWordlist } from '../utils'
export default function NextAPIWordList() {
const [data, setData] = useState<WordListRepsonse>()
const fetchData = () =>
fetchWordlist('http://localhost:3001/api/wordlist').then((response) =>
setData(response)
)
useEffect(() => {
fetchData()
}, [])
return (
<div className="data-fetching-client">
<h3>
Wordlist fetched in the <span>API</span>
</h3>
<div>
{data?.wordList.map((word) => (
<span>{word.word}</span>
))}
</div>
<div>
<button onClick={fetchData}>Refetch!</button>
</div>
</div>
)
}

View File

@@ -24,7 +24,7 @@ export default function ClientWordList() {
))} ))}
</div> </div>
<div> <div>
<button onClick={fetchData}>Revalidate!</button> <button onClick={fetchData}>Refetch!</button>
</div> </div>
</div> </div>
) )

View File

@@ -2,9 +2,9 @@
import { revalidateFetchByTag } from '../actions' import { revalidateFetchByTag } from '../actions'
export default function RevalidateButton() { export default function RevalidateButton(props: { tag?: string }) {
return ( return (
<button onClick={() => revalidateFetchByTag('wordlist')}> <button onClick={() => revalidateFetchByTag(props.tag ?? 'wordlist')}>
Revalidate! Revalidate!
</button> </button>
) )

View File

@@ -1,3 +1,4 @@
import NextAPIWordList from './components/apiside-word-list'
import ClientWordList from './components/clientside-word-list' import ClientWordList from './components/clientside-word-list'
import GoBackButton from './components/go-back-button' import GoBackButton from './components/go-back-button'
import ServerWordList from './components/serverside-word-list' import ServerWordList from './components/serverside-word-list'
@@ -7,6 +8,7 @@ export default function WordList() {
<div className="data-fetching"> <div className="data-fetching">
<ServerWordList /> <ServerWordList />
<ClientWordList /> <ClientWordList />
<NextAPIWordList />
</div> </div>
) )
} }

View File

@@ -1,5 +1,5 @@
const WORDLIST_API_URL = 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 = { export type WordElement = {
word: string word: string
@@ -11,8 +11,8 @@ export type WordListRepsonse = {
} }
// fetch("https://...", { cache: "no-store" }); // fetch("https://...", { cache: "no-store" });
export const fetchWordlist = async () => { export const fetchWordlist = async (url?: string) => {
const wordList: WordListRepsonse = await fetch(WORDLIST_API_URL, { const wordList: WordListRepsonse = await fetch(url ?? WORDLIST_API_URL, {
next: { tags: ['wordlist'] }, next: { tags: ['wordlist'] },
}).then((response) => response.json()) }).then((response) => response.json())

View File

@@ -6,16 +6,18 @@
.data-fetching { .data-fetching {
display: grid; display: grid;
padding: 20rem; padding: 0 10rem;
gap: 8rem; gap: 5rem;
background-color: #fafafa; background-color: #fafafa;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
align-items: center;
height: 100vh;
> * { > * {
background-color: #e9ecef; background-color: #e9ecef;
border-radius: 1.5rem; border-radius: 1.5rem;
padding: 2rem; padding: 2rem;
min-height: 15rem; height: 15rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -85,10 +87,40 @@
> h3 { > h3 {
text-align: center; text-align: center;
font-size: 2.8rem; font-size: 3rem;
font-weight: 100; 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 { &-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;
}
}
} }
} }