Site icon Blog ARC Optimizer

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, .tsou .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/2etc.

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:

  1. Le contenu de la page dépend de données externes : getStaticProps est utilisé
  2. 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 construction
  • getStaticPaths (SSG) : définir des itinéraires dynamiques pour pré-afficher les pages en fonction des données
  • getServerSideProps (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çu
    • previewData – ensemble de données utilisant setPreviewData
    • 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 page
  • revalidate – un nombre facultatif de secondes après lequel la page est régénérée. La valeur par défaut est false – la régénération est effectuée uniquement avec la prochaine build
  • notFound 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].jset 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 contenir postId et commentId
  • si la page utilise un intercepteur de route, par exemple, pages/[...slug], params doit contenir slug 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, [], undefinedou false 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 est falsele chemin manquant sera résolu par un 404 page
  • si fallback est truele comportement de getStaticProps sera:
      • chemins de getStaticPaths sera généré au moment de la construction en utilisant getStaticProps
      • 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.
    • 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 blockingle 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 avec getServerSideProps
  • getStaticPaths ne fonctionne que sur le serveur au moment de la construction
  • getStaticPaths 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 getStaticProps
  • req: Objet HTTP IncomingMessage (message entrant, requête)
  • res: objet de réponse HTTP
  • query: représentation objet de la chaîne de requête
  • preview: voir getStaticProps
  • previewData: voir getStaticProps
  • resolveUrl: 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 incluses
  • locale: voir getStaticProps
  • locales: voir getStaticProps
  • defaultLocale: voir getStaticProps

getServerSideProps devrait renvoyer un objet avec les champs suivants :

  • props – voir getStaticProps
  • notFound – voir getStaticProps
export async function getServerSideProps(context) {
  const res = await fetch('/data')
  const data = await res.json()

  if (!data) {
    return {
      notFound: true
    }
  }

  return {
    props: {}
  }
}
  • redirect – voir getStaticProps
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é serveur
  • getServerSideProps 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
Quitter la version mobile