React에서 tRPC 사용하기
Nx용 AWS 플러그인은 tRPC API를 React 웹사이트와 빠르게 통합할 수 있는 제너레이터를 제공합니다. AWS IAM 및 Cognito 인증 지원과 적절한 오류 처리를 포함해 tRPC 백엔드 연결에 필요한 모든 구성을 자동으로 설정합니다. 이 통합은 프론트엔드와 tRPC 백엔드 간의 완전한 엔드투엔드 타입 안전성을 보장합니다.
필수 조건
섹션 제목: “필수 조건”이 제너레이터를 사용하기 전에 React 애플리케이션이 다음을 충족하는지 확인하세요:
- 애플리케이션을 렌더링하는
main.tsx
파일 존재 - tRPC 프로바이더가 자동으로 주입될
<App/>
JSX 엘리먼트 보유 - 작동하는 tRPC API (tRPC API 제너레이터로 생성된 것)
- Cognito 또는 IAM 인증을 사용하는 API 연결 시
ts#cloudscape-website-auth
제너레이터를 통해 추가된 Cognito 인증
필요한 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 HTLMElement,);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 애플리케이션에 다음 구조를 생성합니다:
디렉터리src
디렉터리components
- <ApiName>ClientProvider.tsx tRPC 클라이언트 설정 및 백엔드 스키마 바인딩. ApiName은 API 이름으로 대체됨
- QueryClientProvider.tsx TanStack React Query 클라이언트 프로바이더
디렉터리hooks
- useSigV4.tsx SigV4를 사용한 HTTP 요청 서명 훅 (IAM 전용)
- use<ApiName>.tsx 해당 백엔드 API용 훅
추가적으로 다음 의존성을 설치합니다:
@trpc/client
@trpc/tanstack-react-query
@tanstack/react-query
aws4fetch
(IAM 인증 사용 시)
생성된 코드 사용
섹션 제목: “생성된 코드 사용”tRPC 훅 사용
섹션 제목: “tRPC 훅 사용”제너레이터는 타입 안전한 tRPC 클라이언트에 접근할 수 있는 use<ApiName>
훅을 제공합니다:
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 공식 문서도 직접 참조할 수 있습니다.