stratégies de rendu et récupération de données (partie 1) / Blogs / Perficient
Cette série est mon CV d’étude Next.js, et malgré son désir d’un Next.js vanille, toutes les fonctionnalités sont applicables avec le SDK Sitecore. C’est semblable au guide J’ai récemment écrit sur GraphQL et vise à réduire la courbe d’apprentissage pour ceux qui y passent à partir d’une autre pile technologique.
Next.js est un framework basé sur React conçu pour développer des applications Web avec des fonctionnalités au-delà de SPA. Comme vous le savez, le principal inconvénient du SPA réside dans les problèmes d’indexation des pages de ces applications par les robots de recherche, ce qui affecte négativement le référencement. Récemment, la situation a commencé à s’améliorer, au moins les pages de ma petite application SPA-PWA ont commencé à être indexées normalement. Cependant, Next.js simplifie considérablement le processus de développement d’applications multipages et hybrides. Il fournit également de nombreuses autres fonctionnalités intéressantes que je vais partager avec vous au cours de ce cours.
Pages
Dans Next.js, une page est un composant React exporté à partir d’un fichier avec un .js
, .jsx
, .ts
ou .tsx
extension située dans le pages
annuaire. Chaque page est associée à un itinéraire par son nom. Par exemple, la page pages/about.js
sera accessible à /about
. Veuillez noter que la page doit être exportée par défaut en utilisant export default
:
export default function About() { return <div>About us</div> }
L’itinéraire pour pages/posts/[id].js
sera dynamique, c’est-à-dire qu’une telle page sera disponible à posts/1
, posts/2
etc.
Par défaut, toutes les pages sont pré-rendues. Cela se traduit par de meilleures performances et un meilleur référencement. Chaque page est associée à un montant minimum de JS. Lorsque la page se charge, le code JS s’exécute, ce qui la rend interactive (ce processus est appelé hydratation).
Il existe 2 formes de pré-rendu : la génération statique (SSG, qui est l’approche recommandée) et le rendu côté serveur (SSR, qui est plus familier à ceux qui travaillent avec d’autres frameworks côté serveur tels que ASP.NET). Le premier formulaire consiste à générer du HTML au moment de la construction et le réutiliser à chaque demande. La seconde est la génération de balisage sur un serveur pour chaque demande. La génération d’un balisage statique est l’approche recommandée pour des raisons de performances.
De plus, vous pouvez utiliser le rendu côté client, où certaines parties de la page sont rendues par JS côté client.
SSG
Il peut générer à la fois des pages avec et sans données.
Sans données le cas est assez évident :
export default function About() { return <div>About us</div> }
Il existe 2 scénarios potentiels pour générer une page statique avec des données:
- Le contenu de la page dépend de données externes :
getStaticProps
est utilisé - Les chemins de page dépendent de données externes : getStaticPaths est utilisé (généralement en conjonction avec
getStaticProps
)
1. Le contenu de la page dépend de données externes
Supposons que la page du blog reçoive une liste de publications provenant d’une source externe, comme un CMS :
// TODO: requesting `posts` export default function Blog({ posts }) { return ( <ul> {posts.map((post) => ( <li key={post.id}>{post.title}</li> ))} </ul> ) }
Pour obtenir les données nécessaires au pré-rendu, le mode asynchrone getStaticProps
La fonction doit être exportée à partir du fichier. Cette fonction est appelée pendant temps de construction et vous permet de transmettre les données reçues à la page sous forme de props
:
export default function Blog({ posts }) { // ... } export async function getStaticProps() { const posts = await (await fetch('https://site.com/posts'))?.json() // the below syntax is important return { props: { posts } } }
2. Les chemins de page dépendent de données externes
Pour gérer le pré-rendu d’une page statique dont les chemins dépendent de données externes, un asynchrone getStaticPaths
la fonction doit être exportée depuis une page dynamique (Par exemple, pages/posts/[id].js
). Cette fonction est appelée au moment de la construction et vous permet de définir des chemins de prérendu :
export default function Post({ post }) { // ... } export async function getStaticPaths() { const posts = await (await fetch('https://site.com/posts'))?.json() // pay attention to the structure of the returned array const paths = posts.map((post) => ({ params: { id: post.id } })) // `fallback: false` means that 404 uses alternative route return { paths, fallback: false } }
pages/posts/[id].js
devrait également exporter le getStaticProps
fonction pour récupérer les données de publication avec le spécifié id
:
export default function Post({ post }) { // ... } export async function getStaticPaths() { // ... } export async function getStaticProps({ params }) { const post = await (await fetch(`https://site.com/posts/${params.id}`)).json() return { props: { post } } }
RSS
Pour gérer le rendu des pages côté serveur, le mode asynchrone getServerSideProps
La fonction doit être exportée à partir du fichier. Cette fonction sera appelée à chaque demande de page.
function Page({ data }) { // ... } export async function getServerSideProps() { const data = await (await fetch('https://site.com/data'))?.json() return { props: { data } } }
Récupération de données
Il existe 3 fonctions pour obtenir les données nécessaires au pré-rendu :
getStaticProps
(SSG) : récupération des données au moment de la constructiongetStaticPaths
(SSG) : définir des itinéraires dynamiques pour pré-afficher les pages en fonction des donnéesgetServerSideProps
(SSR) : obtenez des données sur chaque demande
getStaticProps
La page sur laquelle le fichier asynchrone exporté getStaticProps
est pré-rendu à l’aide des accessoires renvoyés par cette fonction.
export async function getStaticProps(context) { return { props: {} } }
context
est un objet avec les propriétés suivantes :
params
– paramètres de routage pour les pages avec routage dynamique. Par exemple, si le titre de la page est [id].js, les paramètres seront { id : … }preview
– vrai si la page est en mode aperçupreviewData
– ensemble de données utilisantsetPreviewData
locale
– paramètres régionaux actuels (si activé)locales
– paramètres régionaux pris en charge (si activé)defaultLocale
– paramètres régionaux par défaut (si activé)
getStaticProps
renvoie un objet avec les propriétés suivantes :
props
– objet facultatif avec des accessoires pour la pagerevalidate
– un nombre facultatif de secondes après lequel la page est régénérée. La valeur par défaut estfalse
– la régénération est effectuée uniquement avec la prochaine buildnotFound
est une valeur booléenne facultative qui permet de renvoyer un statut 404 et la page correspondante, par exemple :
export async function getStaticProps(context) { const res = await fetch('/data') const data = await res.json() if (!data) { return { notFound: true } } return { props: { data } } }
Noter que notFound
n’est pas requis dans fallback: false
mode, puisque dans ce mode seuls les chemins renvoyés par getStaticPaths
sont pré-rendus.
Notez également que notFound: true
signifie qu’un 404 est renvoyé même si la page précédente a été générée avec succès. Ceci est conçu pour prendre en charge les cas où le contenu généré par l’utilisateur est supprimé.
redirect
est un objet optionnel qui permet d’effectuer des redirections vers des ressources internes et externes, qui doivent avoir la forme{destination: string, permanent: boolean}
:
export async function getStaticProps(context) { const res = await fetch('/data') const data = await res.json() if (!data) { return { redirect: { destination: '/', permanent: false } } } return { props: { data } } }
Note 1: Les redirections au moment de la construction ne sont actuellement pas autorisées. Ces redirections doivent être déclarées à next.config.js
.
Note 2: Modules importés au niveau supérieur pour être utilisés dans getStaticProps
ne sont pas inclus dans l’assemblage client. Cela signifie que le code du serveur, y compris les lectures depuis le système de fichiers ou depuis la base de données, peut être écrit directement dans getStaticProps
.
Note 3: fetch()
dans getStaticProps
ne doit être utilisé que lors de la récupération de ressources provenant de sources externes.
Cas d’utilisation
- les données de rendu sont disponibles au moment de la construction et ne dépendent pas de la demande de l’utilisateur
- les données proviennent d’un CMS sans tête
- les données peuvent être mises en cache en texte brut (et non des données spécifiques à l’utilisateur)
- la page doit être pré-rendue (à des fins de référencement) et doit être très rapide –
getStaticProps
génère des fichiers HTML et JSON qui peuvent être mis en cache à l’aide d’un CDN
Utilisez-le avec TypeScript :
import { GetStaticProps } from 'next' export const getStaticProps: GetStaticProps = async (context) => {}
Pour obtenir les types d’accessoires souhaités, vous devez utiliser InferGetStaticPropsType<typeof getStaticProps>
:
import { InferGetStaticPropsType } from 'next' type Post = { author: string content: string } export const getStaticProps = async () => { const res = await fetch('/posts') const posts: Post[] = await res.json() return { props: { posts } } } export default function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { // posts will be strongly typed as `Post[]` }
ISR : Régénération statique incrémentale
Les pages statiques peuvent être mises à jour après la création de l’application. La régénération statique incrémentielle vous permet d’utiliser la génération statique au niveau de la page individuelle sans avoir à reconstruire l’intégralité du projet.
Exemple:
const Blog = ({ posts }) => ( <ul> {posts.map((post) => ( <li>{post.title}</li> ))} </ul> ) // Executes while building on a server. // It can be called repeatedly as a serverless function when invalidation is enabled and a new request arrives export async function getStaticProps() { const res = await fetch('/posts') const posts = await res.json() return { props: { posts }, // `Next.js` will try regenerating a page: // - when a new request arrives // - at least once every 10 seconds revalidate: 10 // in seconds } } // Executes while building on a server. // It can be called repeatedly as a serverless function if the path has not been previously generated export async function getStaticPaths() { const res = await fetch('/posts') const posts = await res.json() // Retrieving paths for posts pre-rendering const paths = posts.map((post) => ({ params: { id: post.id } })) // Only these paths will be pre-rendered at build time // `{ fallback: 'blocking' }` will render pages serverside in the absence of a corresponding path return { paths, fallback: 'blocking' } } export default Blog
Lorsque vous demandez une page qui a été pré-rendue au moment de la construction, la page mise en cache s’affiche.
- La réponse à toute requête adressée à une telle page avant que 10 secondes ne se soient écoulées est également instantanément renvoyée depuis le cache.
- Après 10 secondes, la requête suivante reçoit également une version mise en cache de la page en réponse
- Après cela, la régénération des pages démarre en arrière-plan
- Après une régénération réussie, le cache est invalidé et une nouvelle page s’affiche. Si la régénération échoue, l’ancienne page reste inchangée
Nuances techniques
getStaticProps
- Depuis
getStaticProps
s’exécute au moment de la construction, il ne peut pas utiliser les données de la requête, telles que les paramètres de requête ou les en-têtes HTTP. getStaticProps
ne fonctionne que sur le serveur, il ne peut donc pas être utilisé pour accéder aux routes internes- lors de l’utilisation
getStaticProps
, non seulement du HTML est généré, mais également un fichier JSON. Ce fichier contient les résultats de getStaticProps et est utilisé par le mécanisme de routage côté client pour transmettre les accessoires aux composants. getStaticProps
ne peut être utilisé que dans un composant de page. En effet, toutes les données nécessaires au rendu de la page doivent être disponibles- en mode développement
getStaticProps
est appelé à chaque demande - le mode aperçu est utilisé pour afficher la page à chaque demande
getStaticPaths
Pages acheminées dynamiquement à partir desquelles les fichiers ont été exportés de manière asynchrone getStaticPaths
La fonction sera pré-générée pour tous les chemins renvoyés par cette fonction.
export async function getStaticPaths() { return { paths: [ params: {} ], fallback: true | false | 'blocking' } }
Paths
paths
définit quels chemins seront pré-rendus. Par exemple, si nous avons une page avec routage dynamique appelée pages/posts/[id].js
et le getStaticPaths
exporté sur cette page renvoie les chemins comme ci-dessous :
return { paths: [ { params: { id: '1' } }, { params: { id: '2' } }, ] }
Puis le posts/1
et posts/2
les pages seront générées statiquement en fonction du pages/posts/[id].js
composant.
Veuillez noter que le nom de chacun params
doit correspondre aux paramètres utilisés sur la page :
- si le titre de la page est
pages/posts/[postId]/[commentId]
alors les paramètres doivent contenirpostId
etcommentId
- si la page utilise un intercepteur de route, par exemple,
pages/[...slug]
,params
doit contenirslug
comme un tableau. Par exemple, si un tel tableau ressemble à['foo', 'bar']
puis la page/foo/bar
sera généré - Si la page utilise un intercepteur de route facultatif, en utilisant
null
,[]
,undefined
oufalse
entraînera le rendu de l’itinéraire de niveau supérieur. Par exemple, appliquer slug: false
àpages/[[...slug]]
générera la page/
Fallback
- si
fallback
estfalse
le chemin manquant sera résolu par un404
page - si
fallback
esttrue
le comportement degetStaticProps
sera:- chemins de
getStaticPaths
sera généré au moment de la construction en utilisantgetStaticProps
- un chemin manquant ne sera pas résolu par un
404
page. Au lieu de cela, une page de secours sera renvoyée en réponse à la demande - Le HTML et le JSON demandés sont générés en arrière-plan. Cela inclut l’appel
getStaticProps
- le navigateur reçoit JSON pour le chemin généré. Ce JSON est utilisé pour afficher automatiquement la page avec les accessoires requis. Du point de vue de l’utilisateur, cela ressemble à une commutation entre la sauvegarde et les pages complètes.
- chemins de
- le nouveau chemin est ajouté à la liste des pages pré-rendues
Veuillez noter: fallback: true
n’est pas pris en charge lors de l’utilisation next export
.
Pages de secours
Dans la version de secours de la page :
- les pages d’accessoires seront vides
- Vous pouvez déterminer qu’une page de secours est affichée à l’aide du routeur :
router.isFallback
sera vrai
// pages/posts/[id].js import { useRouter } from 'next/router' function Post({ post }) { const router = useRouter() // This will be displayed if the page has not yet been generated, // Until `getStaticProps` finishes its work if (router.isFallback) { return <div>Loading...</div> } // post rendering } export async function getStaticPaths() { return { paths: [ { params: { id: '1' } }, { params: { id: '2' } } ], fallback: true } } export async function getStaticProps({ params }) { const res = await fetch(`/posts/${params.id}`) const post = await res.json() return { props: { post }, revalidate: 1 } } export default Post
Dans quels cas pourrait fallback: true
sois utile? Cela peut être utile avec un très grand nombre de pages statiques qui dépendent de données (par exemple, une très grande vitrine de commerce électronique). Nous souhaitons pré-afficher toutes les pages, mais nous savons que la construction prendra une éternité.
Au lieu de cela, nous générons un petit ensemble de pages statiques et utilisons fallback: true
pour le reste. Lors d’une demande de page manquante, l’utilisateur verra un indicateur de chargement pendant un moment (alors que getStaticProps
faire son travail), puis consultez la page elle-même. Après cela, une nouvelle page sera renvoyée en réponse à chaque demande.
Veuillez noter: fallback: true
n’actualise pas les pages générées. La régénération statique incrémentielle est utilisée à cette fin.
Si fallback
est réglé sur blocking
le chemin manquant ne sera pas non plus résolu par le 404
page, mais il n’y aura pas de transition entre les pages de secours et les pages normales. Au lieu de cela, la page demandée sera générée sur le serveur et envoyée au navigateur, et l’utilisateur, après avoir attendu un certain temps, verra immédiatement la page terminée.
Cas d’utilisation pour getStaticPaths
getStaticPaths
est utilisé pour pré-rendre les pages avec un routage dynamique. Utilisez-le avec TypeScript :
import { GetStaticPaths } from 'next' export const getStaticPaths: GetStaticPaths = async () => {}
Nuances techniques :
getStaticPaths
doit être utilisé conjointement avec getStaticProps. Il ne peut pas être utilisé conjointement avecgetServerSideProps
getStaticPaths
ne fonctionne que sur le serveur au moment de la constructiongetStaticPaths
ne peut être exporté que dans un composant de page- en mode développement
getStaticPaths
s’exécute à chaque demande
getServerSideProps
La page à partir de laquelle la fonction asynchrone getServerSideProps est exportée sera rendue à chaque requête à l’aide des accessoires renvoyés par cette fonction.
export async function getServerSideProps(context) { return { props: {} } }
context
est un objet avec les propriétés suivantes :
params
: voir getStaticPropsreq:
Objet HTTP IncomingMessage (message entrant, requête)res
: objet de réponse HTTPquery
: représentation objet de la chaîne de requêtepreview
: voir getStaticPropspreviewData
: voir getStaticPropsresolveUrl
: une version normalisée de l’URL demandée, avec le préfixe _next/data supprimé et les valeurs de chaîne de requête d’origine incluseslocale
: voir getStaticPropslocales
: voir getStaticPropsdefaultLocale
: voir getStaticProps
getServerSideProps
devrait renvoyer un objet avec les champs suivants :
props
– voirgetStaticProps
notFound
– voirgetStaticProps
export async function getServerSideProps(context) { const res = await fetch('/data') const data = await res.json() if (!data) { return { notFound: true } } return { props: {} } }
redirect
– voirgetStaticProps
export async function getServerSideProps(context) { const res = await fetch('/data') const data = await res.json() if (!data) { return { redirect: { destination: '/', permanent: false } } } return { props: {} } }
Pour getServerSideProps
il présente les mêmes caractéristiques et limitations que getStaticProps
.
Cas d’utilisation pour getServerSideProps
getServerSideProps
ne doit être utilisé que lorsque vous devez pré-afficher la page en fonction de données spécifiques à la demande. Utilisez-le avec TypeScript :
import { GetServerSideProps } from 'next' export const getServerSideProps: GetServerSideProps = async () => {}
Pour obtenir les types attendus d’accessoires, vous devez utiliser InferGetServerSidePropsType<typeof getServerSideProps>
:
import { InferGetServerSidePropsType } from 'next' type Data = {} export async function getServerSideProps() { const res = await fetch('/data') const data = await res.json() return { props: { data } } } function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { // ... } export default Page
Nuances techniques:
getServerSideProps
fonctionne uniquement côté serveurgetServerSideProps
ne peut être exporté que dans un composant de page
Récupération de données côté client
Si une page contient des données fréquemment mises à jour, mais qu’en même temps, cette page n’a pas besoin d’être pré-rendue (pour des raisons de référencement), il est alors quasiment possible de récupérer ses données directement côté client.
L’équipe Next.js recommande d’utiliser leur useSWR
hook à cet effet, qui fournit des fonctionnalités telles que la mise en cache des données, l’invalidation du cache, le suivi du focus, les nouvelles tentatives périodiques, etc.
import useSWR from 'swr' const fetcher = (url) => fetch(url).then((res) => res.json()) function Profile() { const { data, error } = useSWR('/api/user', fetcher) if (error) return <div>Error while retrieving the data</div> if (!data) return <div>Loading...</div> return <div>Hello, {data.name}!</div> }
Cependant, vous n’êtes pas limité à cela, vieille bonne requête React fetch()
les fonctions fonctionnent également parfaitement à cet effet.
Ceci conclut la partie 1. Dans la partie 2, nous parlerons des éléments liés à l’interface utilisateur à venir OOB avec Next.js – mises en page, styles et polices, fonctionnalités puissantes, composants d’image et de script, et bien sûr – TypeScript.
Source link