V1 presentation styling + API data fetching
This commit is contained in:
13
presentation/src/app/api/wordlist/route.tsx
Normal file
13
presentation/src/app/api/wordlist/route.tsx
Normal 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)
|
||||
}
|
||||
@@ -37,10 +37,9 @@ export default function Presentation() {
|
||||
function Introduction() {
|
||||
return (
|
||||
<div className="main-presentation-comparation">
|
||||
<h3>Next</h3>
|
||||
<div>
|
||||
<p>Nos da la posibilidad de renderizar desde el servidor</p>
|
||||
</div>
|
||||
<h1>
|
||||
NEXT<span>.JS</span>
|
||||
</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -50,17 +49,21 @@ function Rendering() {
|
||||
<div className="main-presentation-comparation">
|
||||
<h3>Rendering</h3>
|
||||
<div>
|
||||
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:
|
||||
<ul>
|
||||
<li>- By individual route segments </li>
|
||||
<li>- By React with Suspense boundaries </li>
|
||||
</ul>
|
||||
Each chunk is rendered in the server, then, on the client:
|
||||
<ul>
|
||||
<li>
|
||||
1. The HTML is used to immediately show fast preview
|
||||
</li>
|
||||
<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>
|
||||
)
|
||||
@@ -72,25 +75,9 @@ function Strategies() {
|
||||
<h3>Strategies</h3>
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
- Static rendering (default): Good for static pages:
|
||||
Rendered in build time or in the background after data
|
||||
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>
|
||||
<li>- Static rendering (default)</li>
|
||||
<li>- Dynamic rendering: rendered per user request</li>
|
||||
<li>- Streaming: work is split into chunks and streamed</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,33 +87,15 @@ function Strategies() {
|
||||
function Benefits() {
|
||||
return (
|
||||
<div className="main-presentation-benefits">
|
||||
<h3>Beneficios</h3>
|
||||
<h3>Benefits</h3>
|
||||
<div>
|
||||
<ul>
|
||||
<li>
|
||||
- Fetch data directly on the server, performance and
|
||||
load benefits.
|
||||
</li>
|
||||
<li>
|
||||
- Security: sensitive data is kept int the server (API
|
||||
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>
|
||||
<li>- Fetch data directly on the server</li>
|
||||
<li>- Security: sensitive data is kept int the server</li>
|
||||
<li>- Caching</li>
|
||||
<li>- Bundle size reduced</li>
|
||||
<li>- SEO </li>
|
||||
<li>- Streaming</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export default function ClientWordList() {
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={fetchData}>Revalidate!</button>
|
||||
<button onClick={fetchData}>Refetch!</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import { revalidateFetchByTag } from '../actions'
|
||||
|
||||
export default function RevalidateButton() {
|
||||
export default function RevalidateButton(props: { tag?: string }) {
|
||||
return (
|
||||
<button onClick={() => revalidateFetchByTag('wordlist')}>
|
||||
<button onClick={() => revalidateFetchByTag(props.tag ?? 'wordlist')}>
|
||||
Revalidate!
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -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() {
|
||||
<div className="data-fetching">
|
||||
<ServerWordList />
|
||||
<ClientWordList />
|
||||
<NextAPIWordList />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user