ReactからtRPCへ
Nx向けAWSプラグインは、tRPC APIとReactウェブサイトを迅速に統合するためのジェネレータを提供します。AWS IAMおよびCognito認証サポート、適切なエラーハンドリングを含む、tRPCバックエンド接続に必要なすべての設定を構成します。この統合により、フロントエンドとtRPCバックエンド間の完全なエンドツーエンド型安全性が保証されます。
前提条件
このジェネレータを使用する前に、Reactアプリケーションが以下を満たしていることを確認してください:
- アプリケーションをレンダリングする
main.tsx
ファイルが存在すること - tRPCプロバイダが自動注入される
<App/>
JSX要素が含まれていること - tRPCバックエンドジェネレータで生成された動作可能なtRPCバックエンドが存在すること
- CognitoまたはIAM認証を使用するAPIに接続する場合、
ts#cloudscape-website-auth
ジェネレータ経由でCognito Authが追加されていること
必要な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>,);
使用方法
ジェネレータの実行
- インストール Nx Console VSCode Plugin まだインストールしていない場合
- VSCodeでNxコンソールを開く
- クリック
Generate (UI)
"Common Nx Commands"セクションで - 検索
@aws/nx-plugin - api-connection
- 必須パラメータを入力
- クリック
Generate
pnpm nx g @aws/nx-plugin:api-connection
yarn nx g @aws/nx-plugin:api-connection
npx nx g @aws/nx-plugin:api-connection
bunx nx g @aws/nx-plugin:api-connection
変更されるファイルを確認するためにドライランを実行することもできます
pnpm nx g @aws/nx-plugin:api-connection --dry-run
yarn nx g @aws/nx-plugin:api-connection --dry-run
npx nx g @aws/nx-plugin:api-connection --dry-run
bunx nx g @aws/nx-plugin:api-connection --dry-run
オプション
パラメータ | 型 | デフォルト | 説明 |
---|---|---|---|
sourceProject 必須 | string | - | The source project which will call the API |
targetProject 必須 | string | - | The target project containing your API |
ジェネレータの出力
ジェネレータはReactアプリケーション内に以下の構造を作成します:
Directorysrc
Directorycomponents
DirectoryTrpcClients
- index.tsx
- TrpcProvider.tsx 複数のtRPC APIで再利用されるプロバイダ
- TrpcApis.tsx すべてのtRPC API接続を含むオブジェクト
- TrpcClientProviders.tsx tRPCクライアントとバックエンドスキーマのバインディングを設定
- QueryClientProvider.tsx TanStack React Queryクライアントプロバイダ
Directoryhooks
- useSigV4.tsx SigV4によるHTTPリクエスト署名用フック(IAM専用)
- use<ApiName>.tsx 特定のバックエンドAPI用フック。ApiNameはAPI名に解決
さらに、以下の依存関係をインストールします:
@trpc/client
@trpc/tanstack-react-query
@tanstack/react-query
aws4fetch
(IAM認証使用時)
生成コードの使用方法
tRPCフックの使用
ジェネレータが提供するuse<ApiName>
フックを使用して、型安全なtRPCクライアントにアクセスできます:
import { useQuery, useMutation } from '@tanstack/react-query';import { useMyApi } from './hooks/useMyApi';
function MyComponent() { const trpc = useMyApi();
// クエリの例 const { data, isLoading, error } = useQuery(trpc.users.list.queryOptions());
// ミューテーションの例 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> );}
エラーハンドリング
統合にはtRPCエラーを適切に処理する組み込みのエラーハンドリングが含まれます:
function MyComponent() { const trpc = useMyApi();
const { data, error } = useQuery(trpc.users.list.queryOptions());
if (error) { return ( <div> <h2>エラーが発生しました:</h2> <p>{error.message}</p> {error.data?.code && <p>コード: {error.data.code}</p>} </div> ); }
return ( <ul> {data.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> );}
ベストプラクティス
ローディング状態の処理
ユーザーエクスペリエンス向上のため、常にローディング状態とエラー状態を処理してください:
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> );}
楽観的更新
ユーザーエクスペリエンス向上のため楽観的更新を使用します:
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) => { // 進行中のフェッチをキャンセル await queryClient.cancelQueries(trpc.users.list.queryFilter());
// 現在のデータのスナップショット取得 const previousUsers = queryClient.getQueryData( trpc.users.list.queryKey(), );
// 楽観的にユーザーを削除 queryClient.setQueryData(trpc.users.list.queryKey(), (old) => old?.filter((user) => user.id !== userId), );
return { previousUsers }; }, onError: (err, userId, context) => { // エラー時に以前のデータを復元 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)}>削除</button> </li> ))} </ul> );}
データのプリフェッチ
パフォーマンス向上のためデータをプリフェッチ:
function UserList() { const trpc = useMyApi(); const users = useQuery(trpc.users.list.queryOptions()); const queryClient = useQueryClient();
// ホバー時にユーザー詳細をプリフェッチ 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> );}
無限クエリ
ページネーションを無限クエリで処理:
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 ? '読み込み中...' : 'さらに読み込む'} </button> )} </div> );}
無限クエリはcursor
という名前の入力プロパティを持つプロシージャでのみ使用可能です。
型安全性
この統合は完全なエンドツーエンドの型安全性を提供します。IDEはすべてのAPI呼び出しに対して完全なオートコンプリートと型チェックを提供します:
function UserForm() { const trpc = useMyApi();
// ✅ 入力は完全に型付けされる const createUser = trpc.users.create.useMutation();
const handleSubmit = (data: CreateUserInput) => { // ✅ スキーマと一致しない場合は型エラー createUser.mutate(data); };
return <form onSubmit={handleSubmit}>{/* ... */}</form>;}
型はバックエンドのルーターとスキーマ定義から自動的に推論されるため、APIに変更があった場合でもフロントエンドコードをビルドせずに即座に反映されます。
詳細情報
詳細については、tRPC TanStack React Query ドキュメントを参照してください。
直接TanStack Query ドキュメントを参照することもできます。