Article original : How to Build an Image Gallery with NextJS using the Pexels API and Chakra UI
Dans cet article, nous allons créer une galerie d'images avec Next.js en utilisant l'API Pexels et Chakra UI v1, une bibliothèque de composants modulaire et accessible.
Nous utiliserons également le composant Image de Next.js pour optimiser les images récupérées depuis l'API Pexels.
Si vous souhaitez plonger directement dans le code, consultez le dépôt GitHub ici.
Et voici un lien vers la version déployée : https://next-image-gallery.vercel.app/.
Quels concepts et sujets allons-nous couvrir dans cet article ?
- Comment installer et utiliser Chakra UI v1 avec Next.js
- Comment récupérer des données dans Next.js depuis une API
- Comment utiliser le composant Image de Next.js
- Comment configurer les routes dynamiques dans Next.js
Table des matières
- Prérequis
- Comment configurer et installer Next.js
- Comment générer la clé API Pexels
- Comment ajouter un titre à la galerie
- Comment récupérer des données depuis l'API Pexels
- Comment afficher des photos sur la page
- Comment styliser les images avec Chakra UI
- Comment ajouter une fonctionnalité de recherche à la galerie
- Comment ajouter des routes dynamiques aux images
- Conclusion
Maintenant, commençons.
Prérequis
Avant de commencer, vous devriez avoir :
- Des connaissances en HTML, CSS et JavaScript.
- Des connaissances de base en React et Next.js.
- Node et NPM installés sur votre machine de développement locale.
- Un éditeur de code de votre choix.
- React Dev Tools (optionnel)
Si vous avez l'impression que votre progression est entravée parce que vous ne connaissez pas assez ces sujets, consultez https://www.freecodecamp.org/learn. Les modules géniaux disponibles vous mettront en route en un rien de temps.
Comment configurer et installer Next.js
Nous allons utiliser Create Next App pour initialiser rapidement un projet Next.js. Dans le répertoire racine de votre projet, exécutez les commandes suivantes dans le terminal.
npx create-next-app next-image-gallery
cd next-image-gallery
npm run dev
La dernière commande, npm run dev, démarrera le serveur de développement sur le port 3000 de votre système.
Accédez à http://localhost:3000 dans le navigateur. Voici à quoi ressemblera votre application.
Bienvenue sur Next.js - http://localhost:3000
Exécutez la commande suivante pour installer Chakra UI :
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion @chakra-ui/icons
L'étape suivante consiste à nettoyer le code d'exemple généré par create-next-app et à configurer le projet pour utiliser Chakra UI.
- Supprimez les dossiers
stylesetpages/api. - Mettez à jour votre fichier
pages/_app.jscomme ceci :
// pages/_app.js
import { ChakraProvider } from "@chakra-ui/react";
function MyApp({ Component, pageProps }) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
);
}
export default MyApp;
- Modifiez
pages/index.jscomme ceci :
// pages/index.js
import Head from "next/head";
export default function Home() {
return (
<div>
<Head>
<title> Galerie d'images NextJS</title>
<link rel="icon" href="/favicon.ico" />
</Head>
</div>
);
}
Retournez à http://localhost:3000. Vous verrez que l'application est vide, mais le titre a changé pour Galerie d'images NextJS.
Vous pouvez maintenant fermer le serveur de développement.
Comment générer la clé API Pexels
Nous allons utiliser l'API Pexels pour récupérer des images pour notre galerie. Vous devrez créer une clé API Pexels pour authentifier vos requêtes API. L'API elle-même est complètement gratuite à utiliser.
Vous pouvez effectuer jusqu'à 200 requêtes par heure et 20 000 requêtes par mois à l'API Pexels.
Rendez-vous sur https://www.pexels.com/join-consumer/ et créez un nouveau compte sur Pexels.
Créer un nouveau compte
Après avoir rempli vos détails, vous devrez également confirmer votre compte avant de demander une clé API. Vérifiez donc votre boîte de réception et confirmez votre compte Pexels.
Accédez à https://www.pexels.com/api/new/ et remplissez les détails pour une nouvelle clé API et cliquez sur Demander une clé API
Demander une clé API
N'oubliez pas de suivre les directives de l'API. Copiez maintenant la clé API affichée sur la page suivante.
Clé API
Dans le répertoire racine de votre projet, créez un nouveau fichier nommé .env.local pour stocker cette clé API en toute sécurité. Exécutez les commandes suivantes pour créer le fichier :
touch .env.local
À l'intérieur de ce fichier .env.local, créez une nouvelle variable d'environnement nommée PEXELS_API_KEY et collez la clé API là.
NEXT_PUBLIC_PEXELS_API_KEY = ''
Next.js prend en charge le chargement des variables d'environnement depuis .env.local dans process.env.
Par défaut, toutes les variables d'environnement chargées via .env.local ne sont disponibles que dans l'environnement Node.js. Cela signifie qu'elles ne seront pas exposées au navigateur. L'utilisation du préfixe NEXT_PUBLIC_ expose la variable d'environnement au navigateur.
Vous pouvez en lire plus à ce sujet ici.
Comment ajouter un titre à la galerie
Dans cette section, nous allons ajouter un titre à notre galerie.
Importez et ajoutez le composant Box à index.js comme ceci :
//pages/index.js
import Head from "next/head";
import { Box } from "@chakra-ui/react";
export default function Home() {
return (
<div>
<Head>
<title> Galerie d'images NextJS</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Box overflow="hidden" bg="purple.100" minH="100vh"></Box>
</div>
);
}
Accédez à http://localhost:3000. Vous verrez que votre application a une couleur de fond violet clair.
Page vide avec fond violet clair
Voici ce que nous faisons :
- Dans Chakra UI,
bgest la propriété raccourcie pourbackground. En passantbg="purple.100", le fond de l'application change en violet clair. Le nombre après la couleur représente la nuance de la couleur où la plus claire est50, et la plus foncée est900. Voici une image des docs Chakra UI pour mieux illustrer ce point.
Nuances de violet
- Définir
minH="100vh"fait en sorte que l'application ait au moins 100% de la hauteur de l'élément parent.minHest la propriété raccourcie pourmin-height. - Pour se débarrasser des barres de défilement supplémentaires au cas où le contenu déborderait de l'élément parent,
overflow="hidden"est passé.
Pour ajouter un titre, nous allons utiliser les composants Text et Container disponibles dans Chakra UI.
Modifiez l'import Box dans index.js comme ceci :
import { Box, Container, Text } from "@chakra-ui/react";
Maintenant, ajoutez le composant Container à l'intérieur du composant Box.
<Box overflow="hidden" bg="purple.100" minH="100vh">
<Container></Container>
</Box>
Vous ne verrez aucun changement dans votre application, mais le composant Container a ajouté un peu de remplissage horizontal dans votre application, ce qui sera plus apparent après l'ajout du composant Text.
Ajoutez le code suivant à l'intérieur du composant Container :
<Container>
<Text
color="pink.800"
fontWeight="semibold"
mb="1rem"
textAlign="center"
textDecoration="underline"
fontSize={["4xl", "4xl", "5xl", "5xl"]}
>
Galerie d'images NextJS
</Text>
</Container>
Décortiquons le code ci-dessus et discutons-en.
colorest utilisé pour définir la couleur du texte surpink.900.fontWeightest utilisé pour définir l'épaisseur des caractères.mbest une propriété raccourcie pourmargin-bottomet1rem=16px.textAlign="center"aligne le texte au centre.textDecoration="underline"ajoute une ligne sous le texte.fontSize, comme son nom l'indique, définit la taille du texte.
Voici à quoi ressemblera votre application :
Titre - Galerie d'images NextJS
xs: "12px"
sm: "14px"
md: "16px"
lg: "18px"
xl: "20px"
Vous pourriez demander pourquoi il y a quatre valeurs de fontSize sous forme de tableau à l'intérieur des accolades ?
Les {} sont utilisés pour indiquer au parseur JSX d'interpréter l'expression à l'intérieur des {} comme du JavaScript. Ici, {} est utilisé pour passer un tableau pour la valeur de fontSize. Ce tableau est un raccourci pour les requêtes média dans Chakra UI.
Les valeurs sont passées dans un tableau pour rendre le texte réactif et changer la taille de la police en fonction des appareils, c'est-à-dire que le titre sera plus grand sur le bureau.
Chaque index du tableau correspond à un point d'arrêt spécifique et à la valeur de la propriété. Cela signifie que font-size change en fonction du point d'arrêt. Vous pouvez en lire plus à ce sujet ici.
const breakpoints = {
sm: "30em",
md: "48em",
lg: "62em",
xl: "80em",
}
Il suit l'approche "mobile-first", donc la première valeur est pour les petits appareils, et la dernière valeur est pour les appareils de bureau.
Le code ci-dessus générera du CSS comme ceci :
.css-px6f4t {
text-align:center;
-webkit-text-decoration:underline;
text-decoration:underline;
font-size:2.25rem;
color:#702459;
font-weight:600;
margin-bottom:1rem;
}
@media screen and (min-width:30em) {
.css-px6f4t {
font-size:2.25rem;
}
}
@media screen and (min-width:48em) {
.css-px6f4t {
font-size:3rem;
}
}
@media screen and (min-width:62em) {
.css-px6f4t {
font-size:3rem;
}
}
Voici la différence côte à côte de la taille du titre telle que vue dans Polypane.
Polypane
Comment récupérer des données depuis l'API Pexels
Vous avez généré la clé API, alors écrivons le code pour récupérer les données de l'API. Nous allons créer un fichier séparé et définir les fonctions pour récupérer les données à l'intérieur.
Dans le répertoire racine de votre projet, créez un dossier nommé lib. À l'intérieur, créez un fichier nommé api.js.
Exécutez la commande suivante dans le terminal :
mkdir lib
cd lib
touch api.js
Voici l'URL de base de l'API Pexels pour les photos : https://api.pexels.com/v1.
L'API Pexels a trois points de terminaison :
/curatedpour recevoir des photos en temps réel sélectionnées par l'équipe Pexels./searchpour rechercher des photos en fonction d'une requête./photos/:idpour obtenir une seule photo à partir de son identifiant.
Nous utiliserons le point de terminaison /curated pour afficher les photos sélectionnées par l'équipe Pexels sur la page d'accueil de l'application.
Ajoutez le code suivant à api.js :
const API_KEY = process.env.NEXT_PUBLIC_PEXELS_API_KEY;
export const getCuratedPhotos = async () => {
const res = await fetch(
`https://api.pexels.com/v1/curated?page=11&per_page=18`,
{
headers: {
Authorization: API_KEY,
},
}
);
const responseJson = await res.json();
return responseJson.photos;
};
Discutons du code ci-dessus :
- Nous commençons par créer une variable nommée
API_KEYqui accède à la variable d'environnementNEXT_PUBLIC_PEXELS_API_KEYen utilisantprocess.env. - Ensuite, nous créons une fonction asynchrone nommée
getCuratedPhotos()qui utilise la méthodefetch()pour récupérer les données de l'API. - Si vous regardez de plus près l'URL de récupération, vous remarquerez que nous avons ajouté
?page=11&per_page=18après le point de terminaison/curated. Ce sont les paramètres optionnels que vous pouvez passer au point de terminaison/curatedsous forme de chaînes de requête. Ici,page=11signifie envoyer la 11ème page, etper_page=18signifie envoyer 18 photos par page. - Vous pouvez également supprimer ces paramètres optionnels, auquel cas le point de terminaison de l'API vous enverra 15 images de la première page. Vous pouvez obtenir jusqu'à 80 photos en une seule requête.
- La clé API Pexels est passée dans le champ
Authorizationsousheaders. res.json()analyse la réponse au format JSON.responseJsoncontient des champs commepage,per_page, etc., qui ne sont pas utilisés par notre application. Seule la partiephotosde la réponse est donc retournée, qui ressemble à ceci :
[
{
id: 4905078,
width: 7952,
height: 5304,
url: "https://www.pexels.com/photo/ocean-waves-under-blue-sky-4905078/",
photographer: "Nick Bondarev",
photographer_url: "https://www.pexels.com/@nick-bondarev",
photographer_id: 2766954,
src: {
original:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg",
large2x:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
large:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=650&w=940",
medium:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=350",
small:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=130",
portrait:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=1200&w=800",
landscape:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=627&w=1200",
tiny:
"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280",
},
liked: false,
},
];
Dans le champ src, nous avons plusieurs formats d'image différents à choisir. Dans ce tutoriel, nous utiliserons les images de type portrait sur notre page d'accueil. Vous êtes libre d'explorer d'autres formats également.
Au fur et à mesure que nous développons notre application, nous écrirons les fonctions pour rechercher une photo et obtenir une seule photo dans api.js. Pour l'instant, nous utiliserons cette fonction pour afficher une image sur notre page d'accueil ou page principale.
Comment afficher des photos sur la page
Maintenant que nous avons créé la fonction pour récupérer les données, affichons-les sur notre page.
Tout d'abord, importez la fonction getCuratedPhotos() dans index.js.
import Head from "next/head";
import { Box, Container, Text } from "@chakra-ui/react";
import {getCuratedPhotos} from "../lib/api"
Nous allons utiliser la fonction getServerSideProps() disponible dans Next.js et utiliser la fonction getCuratedPhotos() à l'intérieur pour récupérer les données de l'API Pexels et les injecter dans notre page. Vous pouvez en lire plus sur getServerSideProps() ici.
Ajoutez le code suivant en bas de votre fichier index.js :
export async function getServerSideProps() {
const data = await getCuratedPhotos();
return {
props: {
data,
},
};
}
La fonction asynchrone ci-dessus utilise getCuratedPhotos() pour récupérer les images de l'API Pexels et les stocke dans la variable data. Cette variable data est rendue disponible en tant que prop dans la propriété props.
Cette data est disponible en tant que prop, alors ajoutez-la en tant qu'argument dans la fonction du composant Home.
export default function Home({data}) {
...
}
Redémarrez votre serveur de développement, et à l'intérieur de votre composant Home, console.log cette data :
export default function Home({data}) {
console.log(data)
return (
...
}
Rendez-vous sur http://localhost:3000/ et ouvrez la console en appuyant sur CTRL + Shift + J dans Chrome ou CTRL + Shift + K dans Firefox.
console.log(data)
Supprimez le console.log et ajoutez le code suivant en haut de votre fichier index.js pour importer le hook useState() de react.
import React, { useState } from "react";
Nous allons stocker les données de l'API Pexels à l'intérieur d'un état nommé photos. Ajoutez le code suivant avant l'instruction return :
const [photos, setPhotos] = useState(data);
Pour afficher les images, parcourez le tableau photos et passez src.original dans l'attribut src de l'élément img.
Ajoutez le code suivant après le composant Container :
{
photos.map((pic) => (
<img src={pic.src.original} width="500" height="500" />
))
}
Votre application ressemblera maintenant à quelque chose comme ceci :
Affichage des images en utilisant l'élément img
Outre le fait que les images ne sont pas correctement dimensionnées, il y a un autre problème avec l'utilisation de <img> pour afficher les images.
Rendez-vous sur http://localhost:3000/ et ouvrez les Outils de développement, puis l'onglet Réseau (Ctrl+ Shift + E dans Firefox et Ctrl + Shift + J dans Chrome). Cela ressemblera à quelque chose comme ceci :
Onglet Réseau
Maintenant, rechargez votre page. Vous verrez que l'onglet Réseau vide est maintenant rempli de données.
Requête unique
Comme vous pouvez le voir dans l'image ci-dessus, le fichier demandé a une taille de plus de 11 Mo, et cela pour un seul fichier ou image. Les tailles peuvent varier de 10 à 100 Mo ou plus en fonction de la qualité de l'image.
Imaginez que vous avez 80 images sur la page d'accueil de votre application. Est-il judicieux de transférer environ 800 Mo de fichiers chaque fois que quelqu'un visite votre galerie ou votre site web ? Non.
Multiples requêtes
C'est pourquoi aujourd'hui, la plupart des images sur le web sont servies au format WebP. Ce format réduit considérablement la taille de l'image, et vous pouvez à peine détecter une différence visuelle.
Nous devons donc changer le format de l'image en webp, mais la question est, comment ? Doit-on le faire manuellement ? Si oui, ne serait-ce pas chronophage et fastidieux ?
Non, vous n'avez pas besoin de le faire manuellement.
Next.js version 10 est livré avec un support intégré pour l'optimisation des images en utilisant le composant Image. Vous pouvez en lire plus sur cette mise à jour ici.
Remplaçons donc l'élément img par le composant Image de Next.js. Tout d'abord, importez ce composant à l'intérieur de votre index.js comme ceci :
import Image from "next/image";
Mais attendez, avant d'utiliser ce composant dans notre code, nous devons indiquer à Next.js que nos images proviennent d'une ressource externe, comme Pexels.
Arrêtez votre serveur de développement et créez un fichier next.config.js en exécutant la commande suivante :
touch next.config.js
Ajoutez le code suivant à next.config.js :
module.exports = {
images: {
domains: ["images.pexels.com"],
},
};
Et c'est tout. Il existe d'autres configurations comme path, imageSizes, deviceSizes, etc., que vous pouvez ajouter dans le champ images. Mais dans ce tutoriel, nous les laisserons par défaut. Vous pouvez en lire plus sur la configuration ici.
Remplacez img par le composant Image et passez les props, comme indiqué ci-dessous :
{
photos.map((pic) => (
<Image
src={pic.src.portrait}
height={600}
width={400}
alt={pic.url}
/>
))
}
Comme discuté ci-dessus, l'API Pexels fournit différents formats ou tailles de la même image, comme portrait, landscape, tiny, etc., sous le champ src.
Ce tutoriel utilise les images portrait sur la page d'accueil, mais vous êtes libre d'explorer d'autres tailles.
src: {
original: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg",
large2x: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
large: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=650&w=940",
medium: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=350",
small: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&h=130",
portrait: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=1200&w=800",
landscape: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=627&w=1200",
tiny: "https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280",
}
Comme vous pouvez le voir dans l'exemple de champ src ci-dessus, le format portrait de l'image a une largeur de 800 et une hauteur de 1200. Mais il est trop grand pour être affiché sur la page web, alors nous allons le réduire en divisant par 2. Donc 600 et 400 sont passés pour la hauteur et la largeur du composant Image.
Redémarrez votre serveur de développement et rendez-vous sur http://localhost:3000/. Vous verrez que l'application elle-même a exactement le même aspect. Mais cette fois, si vous ouvrez l'onglet Réseau et rechargez la page, vous verrez quelque chose de vraiment magique.
Vos images sont maintenant au format webp, et leurs tailles ont été réduites.
Onglet Réseau
Le composant Image de Next.js a également ajouté le chargement paresseux aux images. Voici un exemple pour expliquer comment et pourquoi vous devriez utiliser le chargement paresseux si vous n'êtes pas familier avec celui-ci.
Même si les images sont maintenant au format webp, est-il nécessaire de charger toutes les images chaque fois que quelqu'un visite votre site web ? Et si le visiteur vient et repart sans faire défiler, est-il judicieux de charger les images en bas de la page ?
Il n'est pas nécessaire de charger les images qu'un utilisateur ou un visiteur ne va pas voir dans la plupart des situations.
Et c'est là que le chargement paresseux vient sauver la journée. Il retarde les requêtes des images jusqu'à ce qu'elles soient nécessaires ou, dans cette situation, lorsque les images apparaissent à l'écran. Cela aide considérablement à réduire le poids initial de la page et augmente les performances du site web.
Si vous vous rendez sur http://localhost:3000/ et faites défiler toutes les images, vous verrez que les images qui ne sont pas dans la fenêtre d'affichage ne sont pas chargées initialement. Mais à mesure que vous faites défiler vers le bas, elles sont transférées et chargées.
Chargement paresseux
Par défaut, la prop layout du composant Image a la valeur intrinsic, ce qui signifie que l'image redimensionnera les dimensions pour les viewports plus petits mais maintiendra les dimensions originales pour les viewports plus grands.
Il existe de nombreuses props que vous pouvez passer au composant Image pour modifier davantage ce composant. Vous pouvez en lire plus à ce sujet ici.
Comment styliser les images avec Chakra UI
Pour styliser les images, nous allons utiliser le composant Wrap de Chakra UI.
Wrap est un composant de mise en page qui ajoute un espace défini entre ses enfants ou images dans ce scénario. Il 'enveloppe' ses enfants automatiquement s'il n'y a pas assez d'espace pour adapter un enfant.
Importez Wrap et WrapItem depuis Chakra UI.
import { Box, Container, Text, Wrap, WrapItem } from "@chakra-ui/react";
WrapItem englobe les enfants individuels tandis que Wrap englobe tous les composants WrapItem.
Modifiez l'expression pour afficher les images comme ceci :
<Wrap px="1rem" spacing={4} justify="center">
{photos.map((pic) => (
<Image src={pic.src.portrait} height={600} width={400} alt={pic.url} />
))}
</Wrap>
Voici ce qui se passe dans le code ci-dessus :
px="1rem"est la propriété raccourcie pourpadding-leftetpadding-right. Cela ajoute un remplissage horizontal de 1 rem.spacing={4}applique un espacement entre chaque enfant. Cela sera visible une fois que chaque image est enveloppée avecWrapItem.justify="center"justifie les images au centre.
Wrap
Maintenant, enveloppez chaque image avec WrapItem. Ajoutez le code suivant à l'intérieur de l'expression JavaScript :
<Wrap px="1rem" spacing={4} justify="center">
{photos.map((pic) => (
<WrapItem
key={pic.id}
boxShadow="base"
rounded="20px"
overflow="hidden"
bg="white"
lineHeight="0"
_hover={{ boxShadow: "dark-lg" }}
>
<Image src={pic.src.portrait} height={600} width={400} alt={pic.url} />
</WrapItem>
))}
</Wrap>
Discutons des props passées à WrapItem une par une :
key={pic.id}donne à chaque image une clé unique afin que React puisse différencier les enfants ou les images.boxShadow="base"ajoute une ombre àWrapItem.rounded="20px"ajoute unborder-radiusde 20px.overflow="hidden"s'assure que l'image ne déborde pas deWrapItemet est vue arrondie.bg="white"ajoute un fond blanc àWrapItem.lineHeight="0"définit la propriétéline-heightà zéro._hover={{ boxShadow: "dark-lg" }}change leboxShadowlorsque vous survolez l'image.
GIF
Vous verrez que spacing={4} a également pris effet depuis que nous avons ajouté WrapItem aux images.
Comment ajouter une fonctionnalité de recherche à la galerie
L'étape suivante consiste à ajouter une fonctionnalité permettant aux utilisateurs de rechercher des images et de leur montrer ces images. Pour cela, nous allons utiliser le point de terminaison /search dans l'API Pexels.
Dans lib/api.js, créez une nouvelle fonction getQueryPhotos() pour rechercher des images en fonction de l'entrée de recherche de l'utilisateur.
export const getQueryPhotos = async (query) => {
const res = await fetch(`https://api.pexels.com/v1/search?query=${query}`, {
headers: {
Authorization: API_KEY,
},
});
const responseJson = await res.json();
return responseJson.photos;
};
La fonction ci-dessus getQueryPhotos() est similaire à getCuratedPhotos mais ici nous avons ajouté un paramètre query à la fonction et modifié le point de terminaison de l'API pour inclure cette query.
`https://api.pexels.com/v1/search?query=${query}`
Importez la fonction getQueryPhotos() dans index.js.
import { getCuratedPhotos, getQueryPhotos } from "../lib/api";
Maintenant, nous allons créer un formulaire pour prendre l'entrée de l'utilisateur et rechercher la même chose.
Nous allons importer et utiliser Input, IconButton, InputRightElement, et InputGroup de Chakra UI pour créer ce formulaire.
Modifiez l'import de Chakra UI comme ceci et ajoutez un import pour SearchIcon :
import {
Box,
Container,
Text,
Wrap,
WrapItem,
Input,
IconButton,
InputRightElement,
InputGroup,
} from "@chakra-ui/react";
import { SearchIcon } from "@chakra-ui/icons";
Ajoutez le code suivant pour le formulaire d'entrée à l'intérieur du composant Container dans le fichier index.js :
<InputGroup pb="1rem">
<Input placeholder="Rechercher une pomme" variant="ghost" />
<InputRightElement
children={
<IconButton
aria-label="Rechercher"
icon={<SearchIcon />}
bg="pink.400"
color="white"
/>
}
/>
</InputGroup>
Voici ce que nous faisons.
InputGroupest utilisé pour regrouper les composantsInputetInputRightElement. Ici,pbest le raccourci pourpadding-bottom.Inputest le champ de saisie où les utilisateurs taperont leurs requêtes. Il a un placeholder "Rechercher une pomme".InputRightElementest utilisé pour ajouter un élément à droite du composantInput. Un bouton d'icône avec l'icône de recherche est passé à la propchildrendeInputRightElement.IconButtonest un composant dans Chakra UI qui est utile lorsque vous voulez une icône comme bouton. L'icône à rendre est passée à l'intérieur de la propicon.
Voici à quoi ressemblera le champ de saisie.
Champ de saisie
Ce formulaire ne fait encore rien. Changeons cela.
Définissez un nouvel état nommé query pour stocker les entrées d'un utilisateur :
export default function Home({ data }) {
const [photos, setPhotos] = useState(data);
const [query, setQuery] = useState("");
...
}
Modifiez le composant Input pour créer une liaison bidirectionnelle entre le champ de saisie et l'état query en utilisant la méthode value et l'événement onChange :
<Input
placeholder="Rechercher une pomme"
variant="ghost"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
Maintenant, créez une fonction nommée handleSubmit() pour gérer l'événement de clic de l'icône de recherche. Pour l'instant, nous allons simplement console.log la requête de saisie et effacer le champ ensuite.
export default function Home({ data }) {
const [photos, setPhotos] = useState(data);
const [query, setQuery] = useState("");
const handleSubmit = async (e) => {
await e.preventDefault();
await console.log(query);
await setQuery("");
};
...
}
Ajoutez cette fonction à l'événement onClick de IconButton :
<InputRightElement
children={
<IconButton
aria-label="Rechercher"
icon={<SearchIcon />}
onClick={handleSubmit}
bg="pink.400"
color="white"
/>
}
/>
Rendez-vous sur http://localhost:3000/ et tapez quelque chose dans le champ de saisie et cliquez sur le bouton de recherche.
console.log(query)
Mais ce formulaire manque encore quelque chose : si vous essayez de rechercher quelque chose en appuyant sur Entrée au lieu du bouton de recherche, il rechargera la page, et la requête ne sera pas enregistrée.
Pour corriger cela, enveloppez le InputGroup avec l'élément form et passez la fonction handleSubmit à l'événement onSubmit comme ceci :
<form onSubmit={handleSubmit}>
<InputGroup pb="1rem">
<Input
placeholder="Rechercher une pomme"
variant="ghost"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<InputRightElement
children={
<IconButton
aria-label="Rechercher"
icon={<SearchIcon />}
onClick={handleSubmit}
bg="pink.400"
color="white"
/>
}
/>
</InputGroup>
</form>
Vous remarquerez que l'appui sur Entrée fonctionnera maintenant.
Maintenant, mettez à jour la fonction handleSubmit comme ceci pour récupérer les images en fonction de la requête de l'utilisateur :
const handleSubmit = async (e) => {
await e.preventDefault();
const res = await getQueryPhotos(query);
await setPhotos(res);
await setQuery("");
}
La fonction ci-dessus passe la variable query à la fonction getQueryPhotos() et les données retournées par la fonction remplacent la valeur précédente dans la variable photos en utilisant setPhotos(res).
Et c'est fait ! Vous pouvez maintenant rechercher des images dans votre application.
Recherche de pomme
Il manque encore quelque chose. Qu'est-ce que c'est ?
Que se passe-t-il si l'utilisateur essaie de rechercher sans aucune requête, comme avec des chaînes vides ? Le code actuel essaiera toujours de faire une requête en utilisant "" et nous rencontrerons l'erreur suivante.

Pour gérer ce problème, nous allons utiliser Toast de Chakra UI.
Importez useToast de Chakra UI :
import {
Box,
Container,
Text,
Wrap,
WrapItem,
Input,
IconButton,
InputRightElement,
InputGroup,
useToast
} from "@chakra-ui/react";
Ajoutez le code suivant juste en dessous de l'endroit où vous avez défini les états pour initialiser Toast.
export default function Home({ data }) {
const [photos, setPhotos] = useState(data);
const [query, setQuery] = useState("");
const toast = useToast();
...
}
Modifiez la fonction handleSubmit() comme ceci :
const handleSubmit = async (e) => {
await e.preventDefault();
if (query == "") {
toast({
title: "Erreur.",
description: "Recherche vide",
status: "error",
duration: 9000,
isClosable: true,
position: "top",
});
} else {
const res = await getQueryPhotos(query);
await setPhotos(res);
await setQuery("");
}
};
Dans le code ci-dessus, nous vérifions si la query est vide ou non avec une simple instruction if/else. Et si elle est vide, alors nous affichons un toast d'erreur avec le texte Recherche vide.
Essayez d'appuyer sur Entrée sans taper quoi que ce soit dans le champ de saisie. Vous verrez un toast comme ceci :
Toast de recherche vide
Comment ajouter des routes dynamiques aux images
Nous allons créer une route dynamique pour chaque image afin que les utilisateurs puissent cliquer sur les images pour obtenir plus d'informations à leur sujet.
Next.js possède une fonctionnalité très intéressante où vous pouvez créer une route dynamique en ajoutant des crochets à une page ([param]), où param peut être des slugs d'URL, des URL conviviales, un ID, etc.
Ici, le param est id, puisque pour obtenir une photo spécifique de l'API Pexels, vous devez fournir son id.
Exécutez les commandes suivantes dans le répertoire racine de votre projet pour créer [id].js dans le répertoire photos sous pages.
mkdir pages/photos
cd pages/photos
touch [id].js
Importez Link de next/link dans index.js. Link aide aux transitions côté client entre les routes. Vous pouvez en lire plus sur Link ici.
import Link from "next/link"
Ajoutez ce Link à chaque image comme ceci :
<Link href={`/photos/${pic.id}`}>
<a>
<Image src={pic.src.portrait} height={600} width={400} alt={pic.url} />
</a>
</Link>
Rendez-vous sur votre application et essayez de cliquer sur n'importe quelle image. Elle affichera une erreur puisque nous avons créé photos/[id].js mais n'avons pas ajouté de code à l'intérieur.
Mais si vous regardez l'URL de cette page, elle sera quelque chose comme ceci :
http://localhost:3000/photos/2977079
Nous allons maintenant créer une troisième fonction nommée getPhotoById() dans lib/api.js pour obtenir une photo spécifique en fonction de son identifiant.
Ajoutez le code suivant à api.js :
export const getPhotoById = async (id) => {
const res = await fetch(`https://api.pexels.com/v1/photos/${id}`, {
headers: {
Authorization: API_KEY,
},
});
const responseJson = await res.json();
return responseJson;
};
Le code ci-dessus utilise le point de terminaison /photos pour obtenir une seule image de l'API Pexels. Vous remarquerez que contrairement à getCuratedPhotos et getQueryPhotos, getPhotoById retourne responseJson et non responseJson.photos.
Ajoutez le code suivant à photos/[id].js :
import { getPhotoById } from "../../lib/api";
import {
Box,
Divider,
Center,
Text,
Flex,
Spacer,
Button,
} from "@chakra-ui/react";
import Image from "next/image";
import Head from "next/head";
import Link from "next/link";
import { InfoIcon, AtSignIcon } from "@chakra-ui/icons";
export default function Photos() {
return (
<Box p="2rem" bg="gray.200" minH="100vh">
<Head>
<title>Image</title>
<link rel="icon" href="/favicon.ico" />
</Head>
</Box>
)
}
Nous avons ajouté une couleur de fond gris clair en utilisant la prop bg et le composant Box. Pour gagner du temps, nous avons importé tous les composants et icônes au préalable.
Créez une fonction getServerSideProps() dans [id].js pour récupérer les données de l'API Pexels.
export async function getServerSideProps({ params }) {
const pic = await getPhotoById(params.id);
return {
props: {
pic,
},
};
}
Redémarrez votre serveur de développement.
Vous pourriez demander comment getServerSideProps() obtient l'id de l'image à partir de l'argument params ?
Puisque cette page utilise une route dynamique, params contient les paramètres de route. Ici, le nom de la page est [id].js, donc params ressemblera à { id: ... }.
Vous pouvez essayer console.log(params) – cela ressemblera à quelque chose comme ceci.
{ id: '4956064' }
Passez cette prop pic à la fonction du composant Photos en tant qu'argument.
export default function Photos({ pic }) {
...
}
Ajoutez le code suivant au composant Box :
```jsx
Image: {pic.id}
{pic.photographer} {"