useUtils
useUtils는 @trpc/react-query로 실행한 쿼리의 캐시 데이터를 관리하는 헬퍼를 제공하는 훅입니다. 각 헬퍼는 @tanstack/react-query의 queryClient 메서드를 감싼 래퍼입니다. useUtils 헬퍼의 세부 옵션과 사용 패턴은 각 헬퍼에 연결된 @tanstack/react-query 문서를 참조하세요.
이 훅은 10.41.0까지 useContext()라는 이름이었으며, 당분간 별칭으로도 유지됩니다.
사용법
useUtils는 라우터의 모든 쿼리에 대한 헬퍼를 담은 객체를 반환합니다. trpc 클라이언트 객체와 같은 방식으로 경로를 따라가면 각 쿼리의 헬퍼에 접근할 수 있습니다. 예를 들어 all 쿼리가 있는 post 라우터를 살펴보겠습니다:
server.tstsimport {initTRPC } from '@trpc/server';import {z } from 'zod';constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),}),});export typeAppRouter = typeofappRouter ;
server.tstsimport {initTRPC } from '@trpc/server';import {z } from 'zod';constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),}),});export typeAppRouter = typeofappRouter ;
이제 컴포넌트에서 useUtils가 제공하는 객체를 탐색하여 post.all 쿼리에 도달하면 쿼리 헬퍼에 접근할 수 있습니다!
MyComponent.tsxtsximport {createTRPCReact } from '@trpc/react-query';import type {AppRouter } from './server';consttrpc =createTRPCReact <AppRouter >();functionMyComponent () {constutils =trpc .useUtils ();utils .post .all .f ;}
MyComponent.tsxtsximport {createTRPCReact } from '@trpc/react-query';import type {AppRouter } from './server';consttrpc =createTRPCReact <AppRouter >();functionMyComponent () {constutils =trpc .useUtils ();utils .post .all .f ;}
헬퍼
useUtils를 통해 접근할 수 있는 헬퍼입니다. 아래 표는 어떤 tRPC 헬퍼가 어떤 @tanstack/react-query 헬퍼 메서드를 래핑하는지 파악하는 데 도움이 됩니다. 각 react-query 메서드는 해당 문서/가이드로 링크됩니다:
| tRPC 헬퍼 래퍼 | @tanstack/react-query 헬퍼 메서드 |
|---|---|
fetch | queryClient.fetchQuery |
prefetch | queryClient.prefetchQuery |
fetchInfinite | queryClient.fetchInfiniteQuery |
prefetchInfinite | queryClient.prefetchInfiniteQuery |
ensureData | queryClient.ensureData |
invalidate | queryClient.invalidateQueries |
refetch | queryClient.refetchQueries |
cancel | queryClient.cancelQueries |
setData | queryClient.setQueryData |
setQueriesData | queryClient.setQueriesData |
getData | queryClient.getQueryData |
setInfiniteData | queryClient.setInfiniteQueryData |
getInfiniteData | queryClient.getInfiniteData |
setMutationDefaults | queryClient.setMutationDefaults |
getMutationDefaults | queryClient.getMutationDefaults |
isMutating | queryClient.isMutating |
reset | queryClient.resetQueries |
❓ 원하는 함수가 여기에 없어요!
@tanstack/react-query에는 아직 tRPC 컨텍스트에 포함되지 않은 많은 함수가 있습니다. 여기에 없는 함수가 필요하다면, 기능 요청을 열기를 통해 요청해 주십시오.
그동안 @tanstack/react-query에서 함수를 직접 가져와서 사용할 수 있습니다. 또한, 이러한 함수를 사용할 때 필터에서 올바른 queryKey를 가져올 수 있도록 getQueryKey도 제공합니다.
프록시 클라이언트
위 react-query 헬퍼 외에도 컨텍스트는 tRPC 프록시 클라이언트를 노출합니다. 이를 통해 추가적인 바닐라 클라이언트를 생성하지 않고도 async/await로 프로시저를 호출할 수 있습니다.
tsximport {useState } from 'react';import {trpc } from './utils/trpc';functionMyComponent () {const [apiKey ,setApiKey ] =useState ('');constutils =trpc .useUtils ();return (<form onSubmit ={async (event ) => {constapiKey = awaitutils .client .apiKey .create .mutate ();setApiKey (apiKey );}}>{/* form content */}</form >);}
tsximport {useState } from 'react';import {trpc } from './utils/trpc';functionMyComponent () {const [apiKey ,setApiKey ] =useState ('');constutils =trpc .useUtils ();return (<form onSubmit ={async (event ) => {constapiKey = awaitutils .client .apiKey .create .mutate ();setApiKey (apiKey );}}>{/* form content */}</form >);}
쿼리 무효화
invalidate 헬퍼를 통해 쿼리를 무효화합니다. invalidate는 다른 헬퍼와 달리 라우터 맵의 모든 레벨에서 사용 가능한 특수 헬퍼입니다. 이는 원하는 경우 단일 쿼리, 전체 라우터, 또는 모든 라우터에서 invalidate를 실행할 수 있음을 의미합니다. 아래 섹션에서 더 자세히 설명합니다.
단일 쿼리 무효화
단일 프로시저와 관련된 쿼리를 무효화하고, 백엔드로의 불필요한 호출을 방지하기 위해 해당 프로시저에 전달된 입력을 기반으로 필터링할 수도 있습니다.
예제 코드
tsximport {trpc } from './utils/trpc';functionMyComponent () {constutils =trpc .useUtils ();constmutation =trpc .post .edit .useMutation ({onSuccess (input ) {utils .post .all .invalidate ();utils .post .byId .invalidate ({id :input .id }); // Will not invalidate queries for other id's},});// [...]}
tsximport {trpc } from './utils/trpc';functionMyComponent () {constutils =trpc .useUtils ();constmutation =trpc .post .edit .useMutation ({onSuccess (input ) {utils .post .all .invalidate ();utils .post .byId .invalidate ({id :input .id }); // Will not invalidate queries for other id's},});// [...]}
전체 라우터에 걸친 무효화
단일 쿼리뿐만 아니라 전체 라우터에 걸친 쿼리 무효화도 가능합니다.
예제 코드
백엔드 코드
server/routers/_app.tstsximport {initTRPC } from '@trpc/server';import {z } from 'zod';export constt =initTRPC .create ();export constappRouter =t .router ({// sub Post routerpost :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),byId :t .procedure .input (z .object ({id :z .string (),}),).query (({input }) => {return {post : {id :input ?.id ,title : 'Look me up!' },};}),edit :t .procedure .input (z .object ({id :z .number (),title :z .string () })).mutation (({input }) => {return {post : {id :input .id ,title :input .title } };}),}),// separate user routeruser :t .router ({all :t .procedure .query (() => {return {users : [{name : 'Dave Grohl' }, {name : 'Haruki Murakami' }] };}),}),});
server/routers/_app.tstsximport {initTRPC } from '@trpc/server';import {z } from 'zod';export constt =initTRPC .create ();export constappRouter =t .router ({// sub Post routerpost :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),byId :t .procedure .input (z .object ({id :z .string (),}),).query (({input }) => {return {post : {id :input ?.id ,title : 'Look me up!' },};}),edit :t .procedure .input (z .object ({id :z .number (),title :z .string () })).mutation (({input }) => {return {post : {id :input .id ,title :input .title } };}),}),// separate user routeruser :t .router ({all :t .procedure .query (() => {return {users : [{name : 'Dave Grohl' }, {name : 'Haruki Murakami' }] };}),}),});
tsximport {trpc } from './utils/trpc';functionMyComponent () {constutils =trpc .useUtils ();constinvalidateAllQueriesAcrossAllRouters = () => {// 1️⃣// All queries on all routers will be invalidatedutils .invalidate ();};constinvalidateAllPostQueries = () => {// 2️⃣// All post queries will be invalidatedutils .post .invalidate ();};constinvalidatePostById = () => {// 3️⃣// All queries in the post router with input {id:1} invalidatedutils .post .byId .invalidate ({id : 1 });};// Example queriestrpc .user .all .useQuery (); // Would only be validated by 1️⃣ only.trpc .post .all .useQuery (); // Would be invalidated by 1️⃣ & 2️⃣trpc .post .byId .useQuery ({id : 1 }); // Would be invalidated by 1️⃣, 2️⃣ and 3️⃣trpc .post .byId .useQuery ({id : 2 }); // would be invalidated by 1️⃣ and 2️⃣ but NOT 3️⃣!// [...]}
tsximport {trpc } from './utils/trpc';functionMyComponent () {constutils =trpc .useUtils ();constinvalidateAllQueriesAcrossAllRouters = () => {// 1️⃣// All queries on all routers will be invalidatedutils .invalidate ();};constinvalidateAllPostQueries = () => {// 2️⃣// All post queries will be invalidatedutils .post .invalidate ();};constinvalidatePostById = () => {// 3️⃣// All queries in the post router with input {id:1} invalidatedutils .post .byId .invalidate ({id : 1 });};// Example queriestrpc .user .all .useQuery (); // Would only be validated by 1️⃣ only.trpc .post .all .useQuery (); // Would be invalidated by 1️⃣ & 2️⃣trpc .post .byId .useQuery ({id : 1 }); // Would be invalidated by 1️⃣, 2️⃣ and 3️⃣trpc .post .byId .useQuery ({id : 2 }); // would be invalidated by 1️⃣ and 2️⃣ but NOT 3️⃣!// [...]}
모든 뮤테이션 시 전체 캐시 무효화
뮤테이션이 정확히 어떤 쿼리를 무효화해야 하는지 추적하는 것은 어렵기 때문에, 모든 뮤테이션의 부수 효과로 _전체 캐시_를 무효화하는 것이 실용적인 해결책이 될 수 있습니다. 요청 배치 처리가 있으므로, 이 무효화는 현재 보고 있는 페이지의 모든 쿼리를 단일 요청으로 다시 가져오게 됩니다.
이를 돕기 위해 기능을 추가했습니다:
tsimport {createTRPCReact } from '@trpc/react-query';import type {AppRouter } from '../server';export consttrpc =createTRPCReact <AppRouter >({overrides : {useMutation : {/*** This function is called whenever a `.useMutation` succeeds**/asynconSuccess (opts ) {/*** @note that order here matters:* The order here allows route changes in `onSuccess` without* having a flash of content change whilst redirecting.**/// Calls the `onSuccess` defined in the `useQuery()`-options:awaitopts .originalFn ();// Invalidate all queries in the react-query cache:awaitopts .queryClient .invalidateQueries ();},},},});
tsimport {createTRPCReact } from '@trpc/react-query';import type {AppRouter } from '../server';export consttrpc =createTRPCReact <AppRouter >({overrides : {useMutation : {/*** This function is called whenever a `.useMutation` succeeds**/asynconSuccess (opts ) {/*** @note that order here matters:* The order here allows route changes in `onSuccess` without* having a flash of content change whilst redirecting.**/// Calls the `onSuccess` defined in the `useQuery()`-options:awaitopts .originalFn ();// Invalidate all queries in the react-query cache:awaitopts .queryClient .invalidateQueries ();},},},});
추가 옵션
쿼리 헬퍼 외에도 useUtils가 반환하는 객체에는 다음 속성들이 포함됩니다:
tsinterfaceProxyTRPCContextProps <TRouter extendsAnyRouter ,TSSRContext > {/*** The `TRPCClient`*/client :TRPCClient <TRouter >;/*** The SSR context when server-side rendering* @default null*/ssrContext ?:TSSRContext | null;/*** State of SSR hydration.* - `false` if not using SSR.* - `prepass` when doing a prepass to fetch queries' data* - `mounting` before TRPCProvider has been rendered on the client* - `mounted` when the TRPCProvider has been rendered on the client* @default false*/ssrState ?:SSRState ;/*** Abort loading query calls when unmounting a component - usually when navigating to a new page* @default false*/abortOnUnmount ?: boolean;}
tsinterfaceProxyTRPCContextProps <TRouter extendsAnyRouter ,TSSRContext > {/*** The `TRPCClient`*/client :TRPCClient <TRouter >;/*** The SSR context when server-side rendering* @default null*/ssrContext ?:TSSRContext | null;/*** State of SSR hydration.* - `false` if not using SSR.* - `prepass` when doing a prepass to fetch queries' data* - `mounting` before TRPCProvider has been rendered on the client* - `mounted` when the TRPCProvider has been rendered on the client* @default false*/ssrState ?:SSRState ;/*** Abort loading query calls when unmounting a component - usually when navigating to a new page* @default false*/abortOnUnmount ?: boolean;}