Dans le développement Web, les opérations CRUD sont des éléments fondamentaux et cruciaux pour la gestion des données. Ils sont omniprésents dans pratiquement toutes les applications, des simples sites Web aux solutions d'entreprise complexes.
Les utilisateurs de NestJS Boilerplate ont déjà pu évaluer et utiliser un nouvel outil puissant - CLI, qui vous permet de créer automatiquement des ressources et leurs propriétés. Avec cet outil, vous pouvez effectuer toutes les opérations CRUD et y ajouter les champs nécessaires sans écrire une seule ligne de code manuellement. Pendant ce temps, comme nous l'avons annoncé à plusieurs reprises, l'écosystème BC Boilerplates comprend un Extensive-React-Boilerplate entièrement compatible pour fournir toutes les fonctionnalités (qui, en principe, peut être une solution complètement indépendante). Explorons maintenant les opérations CRUD du point de vue du frontend.
Dans Next.js, un framework React avec des capacités de rendu côté serveur, ces opérations peuvent être gérées efficacement avec des fonctionnalités qui améliorent les performances, le référencement et l'expérience des développeurs. Auparavant, nous avons publié un article sur un moyen efficace de démarrer un projet NextJS, et maintenant nous souhaitons aller plus loin et analyser les détails et les nuances du travail avec les API dans Next.js.
Comme nous le savons, l'acronyme CRUD signifie Créer, Lire, Mettre à jour et Supprimer. Ce concept représente les opérations fondamentales qui peuvent être effectuées sur n'importe quelle donnée. Envisageons de travailler avec les opérations CRUD en utilisant l'exemple de l'utilisateur du panneau d'administration, où des fonctionnalités telles que l'ajout, la modification et la suppression d'utilisateurs sont implémentées, ainsi que la récupération d'informations les concernant. Les hooks React personnalisés décrits ci-dessous, gérant le traitement des données dans React Query, la pagination, la gestion des erreurs, etc., sont déjà intégrés dans Extensive-React-Boilerplate. Naturellement, vous pouvez exploiter directement ce passe-partout. Dans les sections suivantes, nous partagerons nos idées sur la mise en œuvre de ces fonctionnalités.
Cas d'utilisation : Soumission de données pour créer une nouvelle ressource (par exemple, enregistrement d'un utilisateur, ajout d'un nouveau produit).
Implémentation : Collectez les données du formulaire, envoyez une requête POST au serveur, gérez la réponse et mettez à jour l'interface utilisateur en conséquence.
Observons un exemple. Faire une requête POST à l’API est incorporé à la création d’un nouvel utilisateur. Dans l'extrait ci-dessous, le hook usePostUserService est utilisé pour encapsuler cette logique. Nous avons spécifié la structure des données pour créer un nouvel utilisateur en définissant les types de requête et de réponse, mais omettons cette partie ici pour vous aider à vous concentrer. Vous pouvez voir des informations plus détaillées ou une image plus complète dans le référentiel Extensive-React-Boilerplate car ceci et tous les extraits de code suivants proviennent de là.
Nous allons donc créer un hook personnalisé usePostUserService qui utilise le hook useFetch pour envoyer une requête POST. Il prend les données utilisateur en entrée et les envoie à l'API :
function usePostUserService() { const fetch = useFetch(); return useCallback( (data: UserPostRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users`, { method: "POST", body: JSON.stringify(data), ...requestConfig, }).then(wrapperFetchJsonResponse<UserPostResponse>); }, [fetch] ); }
La fonction wrapperFetchJsonResponse sera examinée plus loin dans cet article lorsque nous aborderons la « gestion des erreurs ».
Cas d'utilisation : Récupérer et afficher une liste de ressources ou une seule ressource (par exemple, récupérer des profils d'utilisateurs et des listes de produits).
Implémentation : Envoyez une requête GET pour récupérer les données, gérer les états de chargement et d'erreur et restituer les données dans l'interface utilisateur.
Dans notre exemple, la lecture de données implique d'envoyer des requêtes GET à l'API pour récupérer les données utilisateur. Cela peut inclure la récupération de tous les utilisateurs avec une pagination, des filtres et le tri ou la récupération d'un seul utilisateur par ID après avoir défini la demande (UsersRequest) et les types de réponse (UsersResponse).
Pour récupérer tous les utilisateurs dans le hook useGetUsersService personnalisé, nous envoyons une requête GET avec des paramètres de requête pour la pagination, les filtres et le tri :
function useGetUsersService() { const fetch = useFetch(); return useCallback( (data: UsersRequest, requestConfig?: RequestConfigType) => { const requestUrl = new URL(`${API_URL}/v1/users`); requestUrl.searchParams.append("page", data.page.toString()); requestUrl.searchParams.append("limit", data.limit.toString()); if (data.filters) { requestUrl.searchParams.append("filters", JSON.stringify(data.filters)); } if (data.sort) { requestUrl.searchParams.append("sort", JSON.stringify(data.sort)); } return fetch(requestUrl, { method: "GET", ...requestConfig, }).then(wrapperFetchJsonResponse<UsersResponse>); }, [fetch] ); }
Pour récupérer un utilisateur unique le hook useGetUserService envoie une requête GET pour récupérer un utilisateur par ID :
function useGetUserService() { const fetch = useFetch(); return useCallback( (data: UserRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users/${data.id}`, { method: "GET", ...requestConfig, }).then(wrapperFetchJsonResponse<UserResponse>); }, [fetch] ); }
Cas d'utilisation : Modification d'une ressource existante (par exemple, mise à jour des informations utilisateur, modification d'un article de blog).
Implémentation : Collectez les données mises à jour, envoyez une requête PUT ou PATCH au serveur, gérez la réponse et mettez à jour l'interface utilisateur.
Effectuons la mise à jour d'un utilisateur existant, ce qui implique d'envoyer une requête PATCH à l'API avec les données utilisateur mises à jour. Pour cela, dans le hook usePatchUserService personnalisé, nous envoyons une requête PATCH avec l'ID utilisateur et les données mises à jour après avoir défini la requête UserPatchRequest et les types de réponse UserPatchResponse :
function usePatchUserService() { const fetch = useFetch(); return useCallback( (data: UserPatchRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users/${data.id}`, { method: "PATCH", body: JSON.stringify(data.data), ...requestConfig, }).then(wrapperFetchJsonResponse<UserPatchResponse>); }, [fetch] ); }
Remarque : L'utilisation de PATCH au lieu de PUT est plus avancée pour les mises à jour partielles des données, tandis que PUT est généralement utilisé pour les mises à jour complètes des ressources.
Cas d'utilisation : Suppression d'une ressource (par exemple, suppression d'un utilisateur ou suppression d'un élément d'une liste).
Mise en œuvre : Envoyez une demande DELETE au serveur, gérez la réponse et mettez à jour l'interface utilisateur pour refléter la suppression.
Dans notre exemple suivant, la suppression d'un utilisateur implique l'envoi d'une requête DELETE à votre API avec l'ID utilisateur. Après avoir défini la requête (UsersDeleteRequest) et les types de réponse (UsersDeleteResponse) dans le hook useDeleteUsersService, une requête DELETE est transmise pour supprimer l'utilisateur par ID.
function usePostUserService() { const fetch = useFetch(); return useCallback( (data: UserPostRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users`, { method: "POST", body: JSON.stringify(data), ...requestConfig, }).then(wrapperFetchJsonResponse<UserPostResponse>); }, [fetch] ); }
Ces hooks résument la complexité de la création de requêtes HTTP et de la gestion des réponses. L'utilisation d'une telle approche garantit une base de code propre et maintenable, car la logique de récupération des données est encapsulée et réutilisable dans vos composants.
D'accord, nous avons traité des exemples de traitement d'opérations CRUD, et regardons de plus près les méthodes d'obtention de données proposées par Next.js car il, en tant que framework, ajoute ses fonctions et optimisations sur React. Il est clair que Next.js, au-delà du CSR (Client-Side Rendering), fournit des fonctionnalités avancées comme SSR (Server-Side Rendering), SSG (Static Site Generation), les routes API intégrées et le rendu hybride. Discutons donc des points communs et des différences dans la récupération de données dans Next.js et React.
Dès que les applications React sont purement côté client, la récupération des données se produit sur le client après le chargement initial de la page. Pour les pages dynamiques qui doivent récupérer des données à chaque fois qu'une page est chargée, il est plus approprié d'utiliser SSR, dans ce cas, les données sont récupérées sur le serveur au moment de la requête.
Dans le cas de SSG, qui convient aux pages statiques où les données ne changent pas souvent, les données sont récupérées au moment de la construction. Ainsi, la méthode getStaticProps nous aide à récupérer les données au moment de la construction (SSG). Si nous avons besoin d'un pré-rendu des pages basé sur des itinéraires dynamiques et des données récupérées au moment de la construction, la méthode getStaticPaths permet de le faire. Il est utilisé conjointement avec getStaticProps pour générer des routes dynamiques au moment de la construction. A noter qu'à partir de Next 14, on peut faire des requêtes directement dans les composants sans ces méthodes, ce qui donne une plus « expérience React ».
La récupération de données côté client avec useQuery peut être utilisée pour les composants interactifs qui doivent récupérer des données côté client, avec un état initial hydraté à partir des données récupérées côté serveur. Pour récupérer des données qui changent fréquemment ou pour ajouter une interactivité côté client, la stratégie useSWR est utile. Il s'agit d'un hook React pour la récupération de données côté client avec mise en cache et revalidation. Il permet de récupérer des données côté client, généralement après le chargement initial de la page. Néanmoins, il ne récupère pas les données au moment de la construction ou sur le serveur pour SSR, mais il peut revalider et récupérer de nouvelles données si nécessaire.
Pour résumer les informations sur les méthodes ci-dessus, nous pouvons jeter un œil au tableau qui fournit un aperçu complet des différentes méthodes de récupération de données dans Next.js, mettant en évidence leurs délais et cas d'utilisation respectifs.
Method | Data Fetching | Timing | Use Case |
---|---|---|---|
getStaticPaths | Static Site Generation (SSG) | At build time | Pre-render pages for dynamic routes based on data available at build time. |
getStaticProps | Static Site Generation (SSG) | At build time | Pre-render pages with static content at build time. Ideal for content that doesn't change frequently. |
getServerSideProps | Server-Side Rendering (SSR) | On each request | Fetch data on the server for each request, providing up-to-date content. Ideal for dynamic content that changes frequently. |
useQuery | Client-Side Rendering (CSR) | After the initial page load | Fetch initial data server-side, hydrate, reduce redundant network requests, Background Refetching. |
useSWR | Client-Side Rendering (CSR) | After the initial page load | Fetch and revalidate data on the client-side, suitable for frequently changing data. |
React Query fournit des hooks pour récupérer, mettre en cache, synchroniser et mettre à jour l'état du serveur, ce qui en fait un excellent outil pour gérer les données dans les applications React et Next.js. Les principaux avantages de son utilisation sont :
QueryClientProvider est un composant fournisseur de contexte qui fournit une instance QueryClient à l'arborescence des composants React. Cette instance est nécessaire pour utiliser des hooks comme useQuery. Pour le configurer, il doit être placé à la racine de votre arborescence de composants et configurer les paramètres globaux pour les requêtes et les mutations tels que le comportement des nouvelles tentatives, la durée du cache, etc. Après cela, il initialise le client React Query et le rend disponible dans toute l'application.
function usePostUserService() { const fetch = useFetch(); return useCallback( (data: UserPostRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users`, { method: "POST", body: JSON.stringify(data), ...requestConfig, }).then(wrapperFetchJsonResponse<UserPostResponse>); }, [fetch] ); }
Alors, pourquoi devrait-il être ajouté au projet ? C'est bénéfique pour :
L'autre fonctionnalité importante fournie par React Query est React Query Devtools - un outil de développement pour inspecter et déboguer les états de React Query. Il peut être facilement ajouté à votre application et accessible via une extension de navigateur ou en tant que composant comme dans l'exemple précédent.
Pendant le développement, React Query Devtools peut être utilisé pour inspecter des requêtes et des mutations individuelles, comprendre pourquoi certaines requêtes effectuent une prélecture et surveiller l'état du cache de requêtes, et voir comment il évolue au fil du temps.
Pour implémenter des contrôles de pagination ou un défilement infini à l'aide des fonctionnalités des bibliothèques, useInfiniteQuery est la solution idéale. Tout d'abord, nous générons des clés uniques pour la mise en cache et la récupération des requêtes dans React Query. La méthode by crée ici une clé unique basée sur les options de tri et de filtrage.
function usePostUserService() { const fetch = useFetch(); return useCallback( (data: UserPostRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users`, { method: "POST", body: JSON.stringify(data), ...requestConfig, }).then(wrapperFetchJsonResponse<UserPostResponse>); }, [fetch] ); }
Pour ce faire, nous utiliserons la fonction useInfiniteQuery de React Query et prendrons le hook useGetUsersService discuté ci-dessus dans la section Opérations de lecture.
function useGetUsersService() { const fetch = useFetch(); return useCallback( (data: UsersRequest, requestConfig?: RequestConfigType) => { const requestUrl = new URL(`${API_URL}/v1/users`); requestUrl.searchParams.append("page", data.page.toString()); requestUrl.searchParams.append("limit", data.limit.toString()); if (data.filters) { requestUrl.searchParams.append("filters", JSON.stringify(data.filters)); } if (data.sort) { requestUrl.searchParams.append("sort", JSON.stringify(data.sort)); } return fetch(requestUrl, { method: "GET", ...requestConfig, }).then(wrapperFetchJsonResponse<UsersResponse>); }, [fetch] ); }
QueryFn récupère ici les données utilisateur en fonction des paramètres de page, de filtre et de tri actuels, et la fonction getNextPageParam détermine la page suivante à récupérer en fonction de la réponse de la dernière page. Lorsque l'utilisateur fait défiler ou demande plus de données, useInfiniteQuery récupère automatiquement l'ensemble de données suivant en fonction du paramètre nextPage - c'est ainsi que se produit le défilement infini. Le temps de cache pour la requête est défini par le paramètre gcTime.
Dans l'ensemble, React Query fournit une solution complète pour gérer et déboguer l'état du serveur dans les applications React. QueryClientProvider garantit une configuration centralisée et cohérente pour toutes les requêtes et mutations, tandis que ReactQueryDevtools propose des outils puissants pour inspecter et comprendre le comportement des requêtes pendant le développement.
La mise en œuvre des opérations CRUD nécessite toujours une gestion appropriée des erreurs pour garantir la convivialité et la fiabilité des applications. Les erreurs de serveur sont généralement associées à l'échec du traitement d'une demande client, à des erreurs dans le code du serveur, à une surcharge des ressources, à une mauvaise configuration de l'infrastructure ou à des pannes de services externes. Pour la gestion des erreurs, Extensive-react-boilerplate suggère d'utiliser la fonction wrapperFetchJsonResponse :
function useGetUserService() { const fetch = useFetch(); return useCallback( (data: UserRequest, requestConfig?: RequestConfigType) => { return fetch(`${API_URL}/v1/users/${data.id}`, { method: "GET", ...requestConfig, }).then(wrapperFetchJsonResponse<UserResponse>); }, [fetch] ); }
Dans cet article, nous avons couvert les opérations CRUD fondamentales et exploré les techniques de récupération de données dans NextJS. Nous avons exploré l'utilisation de React Query pour gérer l'état, en décrivant également les capacités de QueryClientProvider et de ReactQueryDevtools pour le débogage et l'optimisation de la récupération des données. De plus, nous avons discuté de la mise en œuvre de la pagination et du défilement infini pour gérer de grands ensembles de données et abordé la gestion des erreurs pour rendre vos applications plus résilientes et garantir une expérience utilisateur fluide.
En suivant les exemples et techniques décrits dans cet article, vous devriez maintenant être bien équipé pour gérer les opérations CRUD dans vos projets NextJS. Vous pouvez également utiliser notre modèle Extensive-react-boilerplate pour votre projet. Il dispose d'un backend Nestjs-boilerplate entièrement compatible qui implémente la possibilité de travailler avec des opérations CRUD en quelques minutes, sans une seule ligne de code utilisant la CLI, nous avons couvert cela plus en détail ici et ici pour les relations entre entités. Continuez à expérimenter, restez à jour avec les meilleures pratiques et n'hésitez pas à essayer ce passe-partout si vous le trouvez utile.
Notre équipe BC Boilerplates est toujours à la recherche de moyens d'améliorer le développement. Nous aimerions connaître votre avis sur les discussions GitHub ou dans les commentaires ci-dessous.
Grédits complets pour cet article à Olena Vlasenko et Vlad Shchepotin ??
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!