Données structurées React Router 7 : booster SEO et rich snippets

Apprends à configurer les données structurées dans React Router 7 et augmente l’impact SEO de tes pages grâce aux rich snippets et JSON-LD.

5 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

9 modules
57 leçons
Accès à vie
299.49
-35%

À quoi servent les données structurées ?

Tu as déjà optimisé tes balises title et description (voir la leçon Configurer les balises meta SEO). Prochaine étape : aider Google à comprendre ton contenu pour afficher un résultat enrichi (rich snippet) : étoiles, image, durée d’une recette, prix…

Ces informations proviennent d’un bloc JSON-LD placé dans le <head>. L’énorme avantage :

  • zéro impact visuel : c’est invisible pour l’utilisateur ;
  • grande valeur SEO : taux de clic (CTR) boosté jusqu’à +30 %.

Dans React Router 7 (ex-Remix) c’est ultra simple : une resource route ou la fonction meta() suffit.


Installer la typisation Schema .org

Au lieu d’écrire du JSON brut (casse-pieds !), on va utiliser schema-dts : il expose tous les types Schema.org en TypeScript.

install.sh
1
npm install schema-dts

Créer un composant ArticleStructuredData

app/components/ArticleStructuredData.tsx
1
import type { Article } from "schema-dts";
2
3
export function ArticleStructuredData(props: Article) {
4
return (
5
<script
6
type="application/ld+json"
7
dangerouslySetInnerHTML={{ __html: JSON.stringify(props) }}
8
/>
9
);
10
}

Pourquoi un composant ? Tu restes en JSX, tu bénéficies de l’autocomplétion et tu peux l’appeler depuis n’importe quelle route.


Injecter le JSON-LD dans la page article

app/routes/blog.$slug.tsx
1
import { ArticleStructuredData } from "~/components/ArticleStructuredData";
2
import { useLoaderData } from "react-router";
3
import { fetchArticle } from "~/server/articles.server";
4
5
/* ---------------- loader ---------------- */
6
export async function loader({ params }: Route.LoaderArgs) {
7
const article = await fetchArticle({ slug: params.slug });
8
if (!article)
9
throw new Response("Article introuvable", { status: 404 });
10
return article;
11
}
12
13
/* ---------------- composant page ---------------- */
14
export default function ArticlePage() {
15
const article = useLoaderData<typeof loader>();
16
17
return (
18
<>
19
<ArticleStructuredData
20
{"@context"="https://schema.org"}
21
{"@type"="Article"}
22
headline={article.title}
23
image={article.image}
24
datePublished={article.dateCreated.toISOString()}
25
author={{
26
"@type": "Person",
27
name: article.author,
28
}}
29
/* ^? autocomplétion assurée par schema-dts */
30
/>
31
32
{/* …le reste de ton template Markdown / MDX… */}
33
</>
34
);
35
}

Points clés du transcript (reformulés) :

  • Google ne « devine » rien : toutes les infos viennent de ton objet article.
  • On garde un JSON minimaliste – inutile de remplir les 40 champs possibles, concentre-toi sur ceux demandés par la doc Article Google.
  • Le composant se place avant le contenu : Google le lit sans scroller.

Alternative : générer via meta()

Tu préfères la fonction traditionnelle ?

app/routes/blog.$slug.tsx
1
import { generateMeta } from "@forge42/seo-tools/remix/metadata";
2
import { article as articleLD } from "@forge42/seo-tools/structured-data/article";
3
4
export const meta = ({ data }: Route.MetaArgs) =>
5
generateMeta(
6
{
7
title: data.title,
8
description: data.description,
9
url: data.slug, // absolu conseillé
10
},
11
[
12
{
13
"script:ld+json": articleLD({
14
"@type": "Article",
15
headline: data.title,
16
image: data.image,
17
datePublished: data.dateCreated.toISOString(),
18
author: { "@type": "Person", name: data.author },
19
}),
20
},
21
],
22
);

Cette approche colle au transcript : la lib Forge42 écrit le <script> à ta place. À toi de choisir la méthode qui te convient, l’important est que le script atterrisse dans le <head>.


Valider ta structure : deux outils gratuits

  1. Rich Results Test – l’outil officiel Google, affichage desktop + mobile.
  2. Schema Markup Validator – l’ex-outil de test Schema.org, pratique hors connexion.

Copie/colle le HTML généré ou pointe directement ton URL : tu dois voir « Aucun avertissement critique ».


Gérer plusieurs types : Article et Organisation

Les SERP aiment connaître ton entité (marque, blog, association) :

{7-13} app/routes/_root.tsx
1
import { Organization } from "schema-dts";
2
3
export function RootStructuredData() {
4
const org: Organization = {
5
"@context": "https://schema.org",
6
"@type": "Organization",
7
name: "Algomax",
8
url: "https://algomax.fr",
9
logo: "https://algomax.fr/logo.svg",
10
};
11
return (
12
<script
13
type="application/ld+json"
14
dangerouslySetInnerHTML={{ __html: JSON.stringify(org) }}
15
/>
16
);
17
}

Place-le dans app/root.tsx juste avant <Meta />. Ainsi, TOUTES les pages héritent de l’Organisation ; chaque article ajoute ensuite son propre script.


Pièges fréquents

ProblèmeSolution
Script rendu dans le bodyPlace-le via meta() ou dans un composant monté avant le premier <h1>.
URL relatives (/cover.jpg)Convertis en URL absolues (https://…/cover.jpg).
Titre dupliquéSupprime l’ancien <MetaTags> seulement dans la page où tu injectes generateMeta.
Types inconnus (ex. TechArticle)Vérifie dans schema.org ; Google ne supporte pas tout.

Checklist avant de déployer

  • Un seul <script type="application/ld+json"> par type de page.
  • Toutes les URL (url, image, logo) sont absolues.
  • Validation Google : 0 erreur et 0 warning critique.
  • Pages sensibles (/login, /register) : pas de JSON-LD inutile.
  • CI verte : la build ne casse pas (typage schema-dts).
Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours