Aller au contenu

Réagir à tRPC

Le plugin AWS pour Nx fournit un générateur pour intégrer rapidement votre API tRPC avec un site React. Il configure tous les éléments nécessaires pour connecter vos backends tRPC, incluant le support d’authentification AWS IAM et Cognito ainsi qu’une gestion d’erreurs appropriée. Cette intégration offre une sécurité de type end-to-end complète entre votre frontend et vos backends tRPC.

Prérequis

Avant d’utiliser ce générateur, assurez-vous que votre application React possède :

  1. Un fichier main.tsx qui rend votre application
  2. Un élément JSX <App/> où le provider tRPC sera injecté automatiquement
  3. Un backend tRPC fonctionnel (généré via le générateur de backend tRPC)
  4. Une authentification Cognito ajoutée via le générateur ts#cloudscape-website-auth si vous connectez une API utilisant l’authentification Cognito ou IAM
Exemple de structure requise pour main.tsx
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

Exécuter le générateur

  1. Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
  2. Ouvrez la console Nx dans VSCode
  3. Cliquez sur Generate (UI) dans la section "Common Nx Commands"
  4. Recherchez @aws/nx-plugin - api-connection
  5. Remplissez les paramètres requis
    • Cliquez sur Generate

    Options

    Paramètre Type Par défaut Description
    sourceProject Requis string - The source project which will call the API
    targetProject Requis string - The target project containing your API

    Résultat du générateur

    Le générateur crée la structure suivante dans votre application React :

    • Répertoiresrc
      • Répertoirecomponents
        • RépertoireTrpcClients
          • index.tsx
          • TrpcProvider.tsx Provider réutilisable pour plusieurs APIs tRPC
          • TrpcApis.tsx Objet contenant toutes vos connexions d’API tRPC
          • TrpcClientProviders.tsx Configure les clients tRPC et les liaisons avec vos schémas backend
        • QueryClientProvider.tsx Provider du client TanStack React Query
      • Répertoirehooks
        • useSigV4.tsx Hook pour signer les requêtes HTTP avec SigV4 (IAM uniquement)
        • use<ApiName>.tsx Hook dédié à l’API backend spécifiée. ApiName correspond au nom de l’API

    De plus, il installe les dépendances requises :

    • @trpc/client
    • @trpc/tanstack-react-query
    • @tanstack/react-query
    • aws4fetch (si utilisation de l’authentification IAM)

    Utilisation du code généré

    Utiliser le hook tRPC

    Le générateur fournit un hook use<ApiName> donnant accès au client tRPC typé :

    import { useQuery, useMutation } from '@tanstack/react-query';
    import { useMyApi } from './hooks/useMyApi';
    function MyComponent() {
    const trpc = useMyApi();
    // Exemple de query
    const { data, isLoading, error } = useQuery(trpc.users.list.queryOptions());
    // Exemple de mutation
    const mutation = useMutation(trpc.users.create.mutationOptions());
    const handleCreate = () => {
    mutation.mutate({
    name: 'John Doe',
    email: 'john@example.com',
    });
    };
    if (isLoading) return <div>Chargement...</div>;
    return (
    <ul>
    {data.map((user) => (
    <li key={user.id}>{user.name}</li>
    ))}
    </ul>
    );
    }

    Gestion des erreurs

    L’intégration inclut une gestion d’erreurs qui traite correctement les erreurs tRPC :

    function MyComponent() {
    const trpc = useMyApi();
    const { data, error } = useQuery(trpc.users.list.queryOptions());
    if (error) {
    return (
    <div>
    <h2>Erreur survenue :</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>
    );
    }

    Bonnes pratiques

    Gérer les états de chargement

    Toujours gérer 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

    Utilisez les mises à jour optimistes pour améliorer l’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) => {
    // Annuler les requêtes en cours
    await queryClient.cancelQueries(trpc.users.list.queryFilter());
    // Capturer l'état actuel des données
    const previousUsers = queryClient.getQueryData(
    trpc.users.list.queryKey(),
    );
    // Suppression optimiste de l'utilisateur
    queryClient.setQueryData(trpc.users.list.queryKey(), (old) =>
    old?.filter((user) => user.id !== userId),
    );
    return { previousUsers };
    },
    onError: (err, userId, context) => {
    // Restaurer les données précédentes en cas d'erreur
    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)}>Supprimer</button>
    </li>
    ))}
    </ul>
    );
    }

    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();
    // Précharger les détails utilisateur au survol
    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

    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 ? 'Chargement...' : 'Charger plus'}
    </button>
    )}
    </div>
    );
    }

    Il est important de noter que les requêtes infinies ne peuvent être utilisées que pour les procédures possédant une propriété d’entrée nommée cursor.

    Sécurité de type

    L’intégration fournit une sécurité de type complète de bout en bout. Votre IDE offrira l’autocomplétion et la vérification de types pour tous vos appels d’API :

    function UserForm() {
    const trpc = useMyApi();
    // ✅ L'entrée est entièrement typée
    const createUser = trpc.users.create.useMutation();
    const handleSubmit = (data: CreateUserInput) => {
    // ✅ Erreur de type si l'entrée ne correspond pas au schéma
    createUser.mutate(data);
    };
    return <form onSubmit={handleSubmit}>{/* ... */}</form>;
    }

    Les types sont automatiquement inférés depuis les définitions de votre routeur et schémas backend, garantissant que toute modification de votre API est immédiatement reflétée dans votre code frontend sans nécessiter de build.

    Informations complémentaires

    Pour plus d’informations, consultez la documentation tRPC TanStack React Query.

    Vous pouvez également consulter directement la documentation TanStack Query.