React vers tRPC
Nx Plugin for AWS fournit un générateur pour intégrer rapidement votre API tRPC avec un site web React. Il configure tous les paramètres nécessaires pour se connecter à vos backends tRPC, y compris la prise en charge de l’authentification AWS IAM et Cognito et une gestion appropriée des erreurs. L’intégration fournit une sécurité de type de bout en bout complète entre votre frontend et votre ou vos backends tRPC.
Prérequis
Section intitulée « Prérequis »Avant d’utiliser ce générateur, assurez-vous que votre application React dispose de :
- Un fichier
main.tsxqui rend votre application - Un élément JSX
<App/>où le fournisseur tRPC sera automatiquement injecté - Une API tRPC fonctionnelle (générée à l’aide du générateur d’API tRPC)
- Cognito Auth ajouté via le générateur
ts#website#authsi vous vous connectez à une API qui utilise l’authentification Cognito ou IAM
Exemple de structure main.tsx requise
import { StrictMode } from 'react';import * as ReactDOM from 'react-dom/client';import App from './app/app';
const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement,);root.render( <StrictMode> <App /> </StrictMode>,);Utilisation
Section intitulée « Utilisation »Exécuter le générateur
Section intitulée « Exécuter le générateur »pnpm nx g @aws/nx-plugin:connectionyarn nx g @aws/nx-plugin:connectionnpx nx g @aws/nx-plugin:connectionbunx nx g @aws/nx-plugin:connectionVous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
pnpm nx g @aws/nx-plugin:connection --dry-runyarn nx g @aws/nx-plugin:connection --dry-runnpx nx g @aws/nx-plugin:connection --dry-runbunx nx g @aws/nx-plugin:connection --dry-run- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - connection - Remplissez les paramètres requis
- Cliquez sur
Generate
| Paramètre | Type | Par défaut | Description |
|---|---|---|---|
| sourceProject Requis | string | - | Le projet source |
| targetProject Requis | string | - | Le projet cible auquel se connecter |
| sourceComponent | string | - | Le composant source depuis lequel se connecter (nom du composant, chemin relatif à la racine du projet source, ou identifiant du générateur). Utilisez '.' pour sélectionner explicitement le projet comme source. |
| targetComponent | string | - | Le composant cible auquel se connecter (nom du composant, chemin relatif à la racine du projet cible, ou identifiant du générateur). Utilisez '.' pour sélectionner explicitement le projet comme cible. |
| preferInstallDependencies | boolean | true | Indique s'il faut privilégier l'installation des dépendances après l'exécution du générateur. Définir à false pour différer l'installation lors de l'exécution de plusieurs générateurs en lot (une installation s'exécute quand même si nécessaire pour que les générateurs suivants puissent calculer le graphe de projet Nx) ; installer une seule fois à la fin. |
Sortie du générateur
Section intitulée « Sortie du générateur »Le générateur crée la structure suivante dans votre application React :
Répertoiresrc
Répertoirecomponents
- <ApiName>ClientProvider.tsx Configure les clients tRPC et les liaisons avec votre ou vos schémas backend. ApiName sera résolu au nom de l’API
- QueryClientProvider.tsx Fournisseur de client TanStack React Query
Répertoirehooks
- useSigV4.tsx Hook pour signer les requêtes HTTP avec SigV4 (IAM uniquement)
- use<ApiName>.tsx Un hook renvoyant le proxy d’options tRPC pour l’intégration TanStack Query
- use<ApiName>Client.tsx Un hook renvoyant le client tRPC vanilla pour les appels d’API directs
De plus, il installe les dépendances requises :
@trpc/client@trpc/tanstack-react-query@tanstack/react-queryaws4fetch(si vous utilisez l’authentification IAM)event-source-polyfill(si vous utilisez l’API REST, pour la prise en charge des abonnements)
Utilisation du code généré
Section intitulée « Utilisation du code généré »Utilisation du hook de proxy d’options tRPC
Section intitulée « Utilisation du hook de proxy d’options tRPC »Le générateur fournit un hook use<ApiName> qui renvoie un proxy d’options tRPC à utiliser avec les hooks TanStack Query comme useQuery et useMutation :
import { useQuery, useMutation } from '@tanstack/react-query';import { useMyApi } from './hooks/useMyApi';
function MyComponent() { const trpc = useMyApi();
// Example query const { data, isLoading, error } = useQuery(trpc.users.list.queryOptions());
// Example mutation const mutation = useMutation(trpc.users.create.mutationOptions());
const handleCreate = () => { mutation.mutate({ name: 'John Doe', email: 'john@example.com', }); };
if (isLoading) return <div>Loading...</div>;
return ( <ul> {data.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> );}Utilisation du client tRPC vanilla
Section intitulée « Utilisation du client tRPC vanilla »Le hook use<ApiName>Client fournit un accès au client tRPC vanilla, qui est utile pour les appels d’API impératifs et les abonnements :
import { useState } from 'react';import { useMyApiClient } from './hooks/useMyApi';
function MyComponent() { const client = useMyApiClient();
const handleClick = async () => { const result = await client.echo.query({ message: 'Hello!' }); console.log(result);
const mutationResult = await client.users.create.mutate({ name: 'Jane' }); console.log(mutationResult); };
return <button onClick={handleClick}>Call API</button>;}Gestion des erreurs
Section intitulée « Gestion des erreurs »L’intégration inclut une gestion des erreurs intégrée qui traite correctement les erreurs tRPC :
function MyComponent() { const trpc = useMyApi();
const { data, error } = useQuery(trpc.users.list.queryOptions());
if (error) { return ( <div> <h2>Error occurred:</h2> <p>{error.message}</p> {error.data?.code && <p>Code: {error.data.code}</p>} </div> ); }
return ( <ul> {data.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> );}Abonnements (Streaming)
Section intitulée « Abonnements (Streaming) »Lors de la connexion à un backend tRPC d’API REST, le client généré est automatiquement configuré avec un splitLink qui achemine les opérations d’abonnement via httpSubscriptionLink (en utilisant SSE) et les requêtes/mutations régulières via httpLink. Cela signifie que les abonnements fonctionnent immédiatement sans configuration supplémentaire.
Pour plus d’informations sur la façon de définir des procédures d’abonnement dans votre backend, consultez le guide du générateur d’API tRPC.
Utilisation du hook useSubscription
Section intitulée « Utilisation du hook useSubscription »Vous pouvez consommer des abonnements en utilisant le hook useSubscription avec subscriptionOptions du proxy d’options :
import { useSubscription } from '@trpc/tanstack-react-query';import { useMyApi } from './hooks/useMyApi';
function StreamingComponent() { const trpc = useMyApi();
const subscription = useSubscription( trpc.myStream.subscriptionOptions( { query: 'hello' }, { enabled: true, onStarted: () => { console.log('Subscription started'); }, onData: (data) => { console.log('Received:', data.text); }, onError: (error) => { console.error('Subscription error:', error); }, }, ), );
return ( <div> <p>Status: {subscription.status}</p> {subscription.data && <p>Latest: {subscription.data.text}</p>} {subscription.error && <p>Error: {subscription.error.message}</p>} <button onClick={() => subscription.reset()}>Reset</button> </div> );}L’objet subscription fournit :
subscription.data— les données les plus récemment reçuessubscription.error— l’erreur la plus récemment reçuesubscription.status— l’un de'idle','connecting','pending'ou'error'subscription.reset()— réinitialise l’abonnement (utile pour récupérer après des erreurs)
Utilisation du client vanilla
Section intitulée « Utilisation du client vanilla »Alternativement, vous pouvez utiliser le client tRPC vanilla via le hook use<ApiName>Client pour plus de contrôle sur le cycle de vie de l’abonnement :
import { useState, useEffect } from 'react';import { useMyApiClient } from './hooks/useMyApi';
function StreamingComponent() { const client = useMyApiClient(); const [messages, setMessages] = useState<string[]>([]);
useEffect(() => { const subscription = client.myStream.subscribe( { query: 'hello' }, { onData: (data) => { setMessages((prev) => [...prev, data.text]); }, onComplete: () => { console.log('Stream complete'); }, onError: (error) => { console.error('Stream error:', error); }, }, );
// Clean up the subscription on unmount return () => subscription.unsubscribe(); }, [client]);
return ( <ul> {messages.map((msg, i) => ( <li key={i}>{msg}</li> ))} </ul> );}Bonnes pratiques
Section intitulée « Bonnes pratiques »Gérer les états de chargement
Section intitulée « Gérer les états de chargement »Gérez toujours les états de chargement et d’erreur pour une meilleure expérience utilisateur :
function UserList() { const trpc = useMyApi();
const users = useQuery(trpc.users.list.queryOptions());
if (users.isLoading) { return <LoadingSpinner />; }
if (users.error) { return <ErrorMessage error={users.error} />; }
return ( <ul> {users.data.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> );}Mises à jour optimistes
Section intitulée « Mises à jour optimistes »Utilisez des mises à jour optimistes pour une meilleure expérience utilisateur :
import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
function UserList() { const trpc = useMyApi(); const users = useQuery(trpc.users.list.queryOptions()); const queryClient = useQueryClient();
const deleteMutation = useMutation( trpc.users.delete.mutationOptions({ onMutate: async (userId) => { // Cancel outgoing fetches await queryClient.cancelQueries(trpc.users.list.queryFilter());
// Get snapshot of current data const previousUsers = queryClient.getQueryData( trpc.users.list.queryKey(), );
// Optimistically remove the user queryClient.setQueryData(trpc.users.list.queryKey(), (old) => old?.filter((user) => user.id !== userId), );
return { previousUsers }; }, onError: (err, userId, context) => { // Restore previous data on error queryClient.setQueryData( trpc.users.list.queryKey(), context?.previousUsers, ); }, }), );
return ( <ul> {users.map((user) => ( <li key={user.id}> {user.name} <button onClick={() => deleteMutation.mutate(user.id)}>Delete</button> </li> ))} </ul> );}Préchargement des données
Section intitulée « Préchargement des données »Préchargez les données pour de meilleures performances :
function UserList() { const trpc = useMyApi(); const users = useQuery(trpc.users.list.queryOptions()); const queryClient = useQueryClient();
// Prefetch user details on hover const prefetchUser = async (userId: string) => { await queryClient.prefetchQuery(trpc.users.getById.queryOptions(userId)); };
return ( <ul> {users.map((user) => ( <li key={user.id} onMouseEnter={() => prefetchUser(user.id)}> <Link to={`/users/${user.id}`}>{user.name}</Link> </li> ))} </ul> );}Requêtes infinies
Section intitulée « Requêtes infinies »Gérez la pagination avec des requêtes infinies :
function UserList() { const trpc = useMyApi();
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery( trpc.users.list.infiniteQueryOptions( { limit: 10 }, { getNextPageParam: (lastPage) => lastPage.nextCursor, }, ), );
return ( <div> {data?.pages.map((page) => page.users.map((user) => <UserCard key={user.id} user={user} />), )}
{hasNextPage && ( <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}> {isFetchingNextPage ? 'Loading...' : 'Load More'} </button> )} </div> );}Il est important de noter que les requêtes infinies ne peuvent être utilisées que pour les procédures avec une propriété d’entrée nommée cursor.
Sécurité des types
Section intitulée « Sécurité des types »L’intégration fournit une sécurité de type de bout en bout complète. Votre IDE fournira une autocomplétion complète et une vérification de type pour tous vos appels d’API :
function UserForm() { const trpc = useMyApi();
// ✅ Input is fully typed const createUser = trpc.users.create.useMutation();
const handleSubmit = (data: CreateUserInput) => { // ✅ Type error if input doesn't match schema createUser.mutate(data); };
return <form onSubmit={handleSubmit}>{/* ... */}</form>;}Les types sont automatiquement déduits des définitions de routeur et de schéma de votre backend, garantissant que toute modification de votre API est immédiatement reflétée dans votre code frontend sans avoir besoin de construire.
Authentification personnalisée
Section intitulée « Authentification personnalisée »Si votre API tRPC utilise l’authentification Custom (Lambda Authorizer), le fournisseur de client généré inclut des headers d’espace réservé où vous devez ajouter les en-têtes d’autorisation attendus par votre autoriseur. Recherchez les commentaires // TODO: Add headers required by your custom authorizer dans le fichier <ApiName>ClientProvider.tsx généré et remplacez-les par votre logique de jeton ou de clé API.
Plus d’informations
Section intitulée « Plus d’informations »Pour plus d’informations, veuillez vous référer à :