Création de MovieCard et affichage optimisé
Crée un composant MovieCard avec Next/Image et gère l’optimisation des images.
Accéder gratuitement à cette formation
Renseigne ton email pour débloquer immédiatement cette formation gratuite.
Dans cette leçon, tu vas apprendre à extraire l’affichage d’un film dans un composant réutilisable MovieCard et à optimiser les images avec next/image. On verra :
- comment typer les données via Zod
- comment créer un composant Server Component pour afficher un film
- comment configurer Next.js pour charger les images depuis TMDB
- comment intégrer ce composant dans la page d’accueil
1 Pourquoi isoler un composant ?
Lorsque tu récupères la liste des films via l’API The Movie Database, tu obtiens un tableau d’objets { id, title, poster_path, release_date }.
Si tu affiches directement ces données dans la page, tu te retrouves vite avec du JSX dupliqué pour chaque film.
En extrayant un MovieCard, tu gagnes :
- en lisibilité : un endroit unique pour la présentation
- en maintenabilité : si tu veux changer le style ou ajouter un badge, c’est dans
MovieCard.tsx - en optimisation : tu peux spécialiser la configuration de
next/image
Tip
Un composant isolé rend ton code DRY (« Don’t Repeat Yourself ») et facilite l’évolution
2 Définir et typer les données via Zod
Avant d’afficher, on veut s’assurer que les données reçues correspondent bien à notre schéma.
Dans app/server/movies.ts, on a déjà :
1import { z } from 'zod';23export const GetMoviesSchema = z.object({4page: z.number(),5results: z.array(6z.object({7id: z.number(),8title: z.string(),9poster_path: z.string(),10release_date: z.string(),11})12),13});1415export async function getMovies() {16const data = await fetchMovieDb({ url: '/movie/popular' });17const { results } = GetMoviesSchema.parse(data);18return results;19}
On exporte un schéma et on parse la réponse avant de renvoyer
results.
Cela met fin aux erreurs de type et te permet de profiter de l’inférence TypeScript.
Maintenant, définis ton type Movie :
1import { z } from 'zod';2import { GetMoviesSchema } from '../server/movies';34export type Movie = z.infer<typeof GetMoviesSchema>['results'][number];
3 Implémenter le composant MovieCard
Crée un nouveau fichier dédié :
1import Image from 'next/image';2import Link from 'next/link';3import type { Movie } from '../types/movie';45export function MovieCard({ movie }: { movie: Movie }) {6return (7<div className="max-w-[180px] rounded-lg overflow-hidden shadow hover:scale-105 transition">8<div className="relative h-[270px] w-full">9<Image10src={`https://image.tmdb.org/t/p/w500${movie.poster_path}`}11alt={movie.title}12fill13className="object-cover"14sizes="(max-width: 768px) 100vw, 200px"15/>16</div>17<div className="p-2 bg-white dark:bg-gray-800">18<h3 className="font-semibold truncate">{movie.title}</h3>19<p className="text-sm text-gray-500">20{new Date(movie.release_date).getFullYear()}21</p>22<Link23href={`/movies/${movie.id}`}24className="inline-block mt-2 text-blue-600 hover:underline text-sm"25>26Voir plus27</Link>28</div>29</div>30);31}
Points importants :
- Image optimisée avec
fill,object-coveretsizes - Border radius et shadow pour un rendu soigné
- Un lien
<Link>pour la navigation vers la page détail
4 Configurer Next.js pour les images distantes
Par défaut, Next.js bloque les domaines externes.
Ouvre next.config.js et ajoute les remotePatterns :
1module.exports = {2images: {3remotePatterns: [4{5protocol: 'https',6hostname: 'image.tmdb.org',7port: '',8pathname: '/t/p/**',9},10],11},12};
Après ça, tu pourras charger les affiches sans erreur.
5 Afficher la liste avec MovieCard
Modifie ta page d’accueil pour utiliser MovieCard :
1import { getMovies } from './server/movies';2import { MovieCard } from './components/MovieCard';34export default async function Home() {5const movies = await getMovies();6return (7<main className="p-8 grid grid-cols-fluid gap-6">8<h1 className="col-span-full text-4xl font-bold">Films populaires</h1>9{movies.map(movie => (10<MovieCard key={movie.id} movie={movie} />11))}12</main>13);14}
La grille CSS grid-cols-fluid peut être définie dans ton globals.css :
1@layer utilities {2.grid-cols-fluid {3grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));4}5}
Points clés
- Zod garantit un typage solide et évite les
any MovieCardisole la présentation et optimisenext/imageremotePatternspermet de charger des images TMDB- L’usage de
sizesetfillréduit la bande passante
Exercices rapides
- Ajouter un placeholder : Dans
MovieCard, utilise<Image placeholder="blur" blurDataURL="..." />. - Badge “Nouvelle sortie” : Affiche un badge si
release_dateest dans les 30 derniers jours. - Composant SeriesCard : Inspire-toi de
MovieCardpour construire unSeriesCardavecfirst_air_date.