Skip to main content
Version: 11.x

使用 React 服务器组件设置

本指南概述了如何将 tRPC 与 React Server Components (RSC) 框架(例如 Next.js App Router)结合使用。请注意,RSC 本身解决了许多与 tRPC 旨在解决的问题相同的问题,因此你可能根本不需要 tRPC。

¥This guide is an overview of how one may use tRPC with a React Server Components (RSC) framework such as Next.js App Router. Be aware that RSC on its own solves a lot of the same problems tRPC was designed to solve, so you may not need tRPC at all.

也没有一种万能的方法可以将 tRPC 与 RSC 集成,因此请将本指南作为起点,并根据你的需求和偏好进行调整。

¥There are also not a one-size-fits-all way to integrate tRPC with RSCs, so see this guide as a starting point and adjust it to your needs and preferences.

信息

如果你正在寻找如何将 tRPC 与服务器操作一起使用,请查看 Julius 的这篇博文

¥If you're looking for how to use tRPC with Server Actions, check out this blog post by Julius.

提醒

请阅读 React Query 的 高级服务器渲染 文档,然后再继续了解不同类型的服务器渲染以及应避免哪些错误。

¥Please read React Query's Advanced Server Rendering docs before proceeding to understand the different types of server rendering and what footguns to avoid.

将 tRPC 添加到现有项目

¥Add tRPC to existing projects

1. 安装依赖

¥ Install deps

npm install @trpc/server @trpc/client @trpc/tanstack-react-query @tanstack/react-query@latest zod client-only server-only

2. 创建 tRPC 路由

¥ Create a tRPC router

使用 initTRPC 函数在 trpc/init.ts 中初始化你的 tRPC 后端,并创建你的第一个路由。我们将在这里制作一个简单的 "你好世界" 路由和程序 - 但有关创建 tRPC API 的详细信息,你应该参考 快速入门指南后端使用文档 以获取 tRPC 信息。

¥Initialize your tRPC backend in trpc/init.ts using the initTRPC function, and create your first router. We're going to make a simple "hello world" router and procedure here - but for deeper information on creating your tRPC API you should refer to the Quickstart guide and Backend usage docs for tRPC information.

信息

此处使用的文件名不受 tRPC 强制执行。你可以使用任何你想要的文件结构。

¥The file names used here are not enforced by tRPC. You may use any file structure you wish.

View sample backend
trpc/init.ts
ts
import { initTRPC } from '@trpc/server';
import { cache } from 'react';
export const createTRPCContext = cache(async () => {
/**
* @see: https://trpc.nodejs.cn/docs/server/context
*/
return { userId: 'user_123' };
});
// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create({
/**
* @see https://trpc.nodejs.cn/docs/server/data-transformers
*/
// transformer: superjson,
});
// Base router and procedure helpers
export const createTRPCRouter = t.router;
export const createCallerFactory = t.createCallerFactory;
export const baseProcedure = t.procedure;
trpc/init.ts
ts
import { initTRPC } from '@trpc/server';
import { cache } from 'react';
export const createTRPCContext = cache(async () => {
/**
* @see: https://trpc.nodejs.cn/docs/server/context
*/
return { userId: 'user_123' };
});
// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create({
/**
* @see https://trpc.nodejs.cn/docs/server/data-transformers
*/
// transformer: superjson,
});
// Base router and procedure helpers
export const createTRPCRouter = t.router;
export const createCallerFactory = t.createCallerFactory;
export const baseProcedure = t.procedure;

trpc/routers/_app.ts
ts
import { z } from 'zod';
import { baseProcedure, createTRPCRouter } from '../init';
export const appRouter = createTRPCRouter({
hello: baseProcedure
.input(
z.object({
text: z.string(),
}),
)
.query((opts) => {
return {
greeting: `hello ${opts.input.text}`,
};
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;
trpc/routers/_app.ts
ts
import { z } from 'zod';
import { baseProcedure, createTRPCRouter } from '../init';
export const appRouter = createTRPCRouter({
hello: baseProcedure
.input(
z.object({
text: z.string(),
}),
)
.query((opts) => {
return {
greeting: `hello ${opts.input.text}`,
};
}),
});
// export type definition of API
export type AppRouter = typeof appRouter;

note

The backend adapter depends on your framework and how it sets up API routes. The following example sets up GET and POST routes at /api/trpc/* using the fetch adapter in Next.js.

app/api/trpc/[trpc]/route.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createTRPCContext } from '~/trpc/init';
import { appRouter } from '~/trpc/routers/_app';
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext: createTRPCContext,
});
export { handler as GET, handler as POST };
app/api/trpc/[trpc]/route.ts
ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createTRPCContext } from '~/trpc/init';
import { appRouter } from '~/trpc/routers/_app';
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext: createTRPCContext,
});
export { handler as GET, handler as POST };

3. 创建查询客户端工厂

¥ Create a Query Client factory

创建一个共享文件 trpc/query-client.ts,导出一个创建 QueryClient 实例的函数。

¥Create a shared file trpc/query-client.ts that exports a function that creates a QueryClient instance.

trpc/query-client.ts
ts
import {
defaultShouldDehydrateQuery,
QueryClient,
} from '@tanstack/react-query';
import superjson from 'superjson';
export function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 30 * 1000,
},
dehydrate: {
// serializeData: superjson.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) ||
query.state.status === 'pending',
},
hydrate: {
// deserializeData: superjson.deserialize,
},
},
});
}
trpc/query-client.ts
ts
import {
defaultShouldDehydrateQuery,
QueryClient,
} from '@tanstack/react-query';
import superjson from 'superjson';
export function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 30 * 1000,
},
dehydrate: {
// serializeData: superjson.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) ||
query.state.status === 'pending',
},
hydrate: {
// deserializeData: superjson.deserialize,
},
},
});
}

我们在这里设置一些默认选项:

¥We're setting a few default options here:

  • staleTime:使用 SSR,我们通常希望将某个默认的 staleTime 设置为高于 0,以避免在客户端上立即重新获取。

    ¥staleTime: With SSR, we usually want to set some default staleTime above 0 to avoid refetching immediately on the client.

  • shouldDehydrateQuery:这是一个确定查询是否应脱水的函数。由于 RSC 传输协议支持通过网络进行水合承诺,因此我们扩展了 defaultShouldDehydrateQuery 函数以包括仍处于待处理的查询。这将使我们能够在树上部的服务器组件中开始预取,然后在更下方的客户端组件中使用该承诺。

    ¥shouldDehydrateQuery: This is a function that determines whether a query should be dehydrated or not. Since the RSC transport protocol supports hydrating promises over the network, we extend the defaultShouldDehydrateQuery function to also include queries that are still pending. This will allow us to start prefetching in a server component high up the tree, then consuming that promise in a client component further down.

  • serializeDatadeserializeData(可选):如果你在上一步中设置了 数据转换器,请设置此选项以确保在服务器-客户端边界上传输查询客户端时正确序列化数据。

    ¥serializeData and deserializeData (optional): If you set up a data transformer in the previous step, set this option to make sure the data is serialized correctly when hydrating the query client over the server-client boundary.

4. 为客户端组件创建 tRPC 客户端

¥ Create a tRPC client for Client Components

trpc/client.tsx 是从客户端组件使用 tRPC API 时的入口点。在这里,导入你的 tRPC 路由的类型定义并使用 createTRPCContext 创建类型安全的钩子。我们还将从此文件中导出上下文提供程序。

¥The trpc/client.tsx is the entrypoint when consuming your tRPC API from client components. In here, import the type definition of your tRPC router and create typesafe hooks using createTRPCContext. We'll also export our context provider from this file.

trpc/client.tsx
tsx
'use client';
// ^-- to make sure we can mount the Provider from a server component
import type { QueryClient } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { createTRPCContext } from '@trpc/tanstack-react-query';
import { useState } from 'react';
import { makeQueryClient } from './query-client';
import type { AppRouter } from './routers/_app';
export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>();
let browserQueryClient: QueryClient;
function getQueryClient() {
if (typeof window === 'undefined') {
// Server: always make a new query client
return makeQueryClient();
}
// Browser: make a new query client if we don't already have one
// This is very important, so we don't re-make a new client if React
// suspends during the initial render. This may not be needed if we
// have a suspense boundary BELOW the creation of the query client
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
function getUrl() {
const base = (() => {
if (typeof window !== 'undefined') return '';
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return 'http://localhost:3000';
})();
return `${base}/api/trpc`;
}
export function TRPCReactProvider(
props: Readonly<{
children: React.ReactNode;
}>,
) {
// NOTE: Avoid useState when initializing the query client if you don't
// have a suspense boundary between this and the code that may
// suspend because React will throw away the client on the initial
// render if it suspends and there is no boundary
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
httpBatchLink({
// transformer: superjson, <-- if you use a data transformer
url: getUrl(),
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{props.children}
</TRPCProvider>
</QueryClientProvider>
);
}
trpc/client.tsx
tsx
'use client';
// ^-- to make sure we can mount the Provider from a server component
import type { QueryClient } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { createTRPCContext } from '@trpc/tanstack-react-query';
import { useState } from 'react';
import { makeQueryClient } from './query-client';
import type { AppRouter } from './routers/_app';
export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>();
let browserQueryClient: QueryClient;
function getQueryClient() {
if (typeof window === 'undefined') {
// Server: always make a new query client
return makeQueryClient();
}
// Browser: make a new query client if we don't already have one
// This is very important, so we don't re-make a new client if React
// suspends during the initial render. This may not be needed if we
// have a suspense boundary BELOW the creation of the query client
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
function getUrl() {
const base = (() => {
if (typeof window !== 'undefined') return '';
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return 'http://localhost:3000';
})();
return `${base}/api/trpc`;
}
export function TRPCReactProvider(
props: Readonly<{
children: React.ReactNode;
}>,
) {
// NOTE: Avoid useState when initializing the query client if you don't
// have a suspense boundary between this and the code that may
// suspend because React will throw away the client on the initial
// render if it suspends and there is no boundary
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
httpBatchLink({
// transformer: superjson, <-- if you use a data transformer
url: getUrl(),
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{props.children}
</TRPCProvider>
</QueryClientProvider>
);
}

将提供程序挂载到应用的根目录中(例如,使用 Next.js 时为 app/layout.tsx)。

¥Mount the provider in the root of your application (e.g. app/layout.tsx when using Next.js).

5. 为服务器组件创建 tRPC 调用者

¥ Create a tRPC caller for Server Components

要从服务器组件预取查询,我们从路由创建代理。如果你的路由位于单独的服务器上,你还可以传入客户端。

¥To prefetch queries from server components, we create a proxy from our router. You can also pass in a client if your router is on a separate server.

trpc/server.tsx
tsx
import 'server-only'; // <-- ensure this file cannot be imported from the client
import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
import { cache } from 'react';
import { createTRPCContext } from './init';
import { makeQueryClient } from './query-client';
import { appRouter } from './routers/_app';
// IMPORTANT: Create a stable getter for the query client that
// will return the same client during the same request.
export const getQueryClient = cache(makeQueryClient);
export const trpc = createTRPCOptionsProxy({
ctx: createTRPCContext,
router: appRouter,
queryClient: getQueryClient,
});
// If your router is on a separate server, pass a client:
createTRPCOptionsProxy({
client: createTRPCClient({
links: [httpLink({ url: '...' })],
}),
queryClient: getQueryClient,
});
trpc/server.tsx
tsx
import 'server-only'; // <-- ensure this file cannot be imported from the client
import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
import { cache } from 'react';
import { createTRPCContext } from './init';
import { makeQueryClient } from './query-client';
import { appRouter } from './routers/_app';
// IMPORTANT: Create a stable getter for the query client that
// will return the same client during the same request.
export const getQueryClient = cache(makeQueryClient);
export const trpc = createTRPCOptionsProxy({
ctx: createTRPCContext,
router: appRouter,
queryClient: getQueryClient,
});
// If your router is on a separate server, pass a client:
createTRPCOptionsProxy({
client: createTRPCClient({
links: [httpLink({ url: '...' })],
}),
queryClient: getQueryClient,
});

使用你的 API

¥Using your API

现在你可以在应用中使用 tRPC API。虽然你可以像在任何其他 React 应用中一样在客户端组件中使用 React Query 钩子,但我们可以通过在树上层服务器组件中预取查询来利用 RSC 功能。你可能熟悉这个概念,因为 "获取时渲染" 通常作为加载器实现。这意味着请求会尽快触发,但不会暂停,直到使用 useQueryuseSuspenseQuery 钩子需要数据为止。

¥Now you can use your tRPC API in your app. While you can use the React Query hooks in client components just like you would in any other React app, we can take advantage of the RSC capabilities by prefetching queries in a server component high up the tree. You may be familiar with this concept as "render as you fetch" commonly implemented as loaders. This means the request fires as soon as possible but without suspending until the data is needed by using the useQuery or useSuspenseQuery hooks.

此方法利用了 Next.js 应用路由的流式处理功能,在服务器上启动查询,并在数据可用时将其流式传输到客户端。它优化了浏览器中第一个字节的读取时间和数据提取时间,从而加快了页面加载速度。但是,在数据流入之前,greeting.data 可能最初是 undefined

¥This approach leverages Next.js App Router's streaming capabilities, initiating the query on the server and streaming data to the client as it becomes available. It optimizes both the time to first byte in the browser and the data fetch time, resulting in faster page loads. However, greeting.data may initially be undefined before the data streams in.

如果你希望避免这种初始未定义状态,可以将 prefetchQuery 调用 await。这可确保客户端上的查询在首次渲染时始终具有数据,但这也带来了一些权衡。 - 页面加载速度会变慢,因为服务器必须先完成查询,然后才能将 HTML 发送到客户端。

¥If you prefer to avoid this initial undefined state, you can await the prefetchQuery call. This ensures the query on the client always has data on first render, but it comes with a tradeoff - the page will load more slowly since the server must complete the query before sending HTML to the client.

app/page.tsx
tsx
import { dehydrate, HydrationBoundary } from '@tanstack/react-query';
import { getQueryClient, trpc } from '~/trpc/server';
import { ClientGreeting } from './client-greeting';
export default async function Home() {
const queryClient = getQueryClient();
void queryClient.prefetchQuery(
trpc.hello.queryOptions({
/** input */
}),
);
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrationBoundary>
);
}
app/page.tsx
tsx
import { dehydrate, HydrationBoundary } from '@tanstack/react-query';
import { getQueryClient, trpc } from '~/trpc/server';
import { ClientGreeting } from './client-greeting';
export default async function Home() {
const queryClient = getQueryClient();
void queryClient.prefetchQuery(
trpc.hello.queryOptions({
/** input */
}),
);
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrationBoundary>
);
}
app/client-greeting.tsx
tsx
'use client';
// <-- hooks can only be used in client components
import { useQuery } from '@tanstack/react-query';
import { useTRPC } from '~/trpc/client';
export function ClientGreeting() {
const trpc = useTRPC();
const greeting = useQuery(trpc.hello.queryOptions({ text: 'world' }));
if (!greeting.data) return <div>Loading...</div>;
return <div>{greeting.data.greeting}</div>;
}
app/client-greeting.tsx
tsx
'use client';
// <-- hooks can only be used in client components
import { useQuery } from '@tanstack/react-query';
import { useTRPC } from '~/trpc/client';
export function ClientGreeting() {
const trpc = useTRPC();
const greeting = useQuery(trpc.hello.queryOptions({ text: 'world' }));
if (!greeting.data) return <div>Loading...</div>;
return <div>{greeting.data.greeting}</div>;
}
提示

你还可以创建 prefetchHydrateClient 辅助函数,使其更简洁、更易重用:

¥You can also create a prefetch and HydrateClient helper functions to make it a bit more consice and reusable:

trpc/server.tsx
tsx
export function HydrateClient(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();
return (
<HydrationBoundary state={dehydrate(queryClient)}>
{props.children}
</HydrationBoundary>
);
}
export function prefetch<T extends ReturnType<TRPCQueryOptions<any>>>(
queryOptions: T,
) {
const queryClient = getQueryClient();
if (queryOptions.queryKey[1]?.type === 'infinite') {
void queryClient.prefetchInfiniteQuery(queryOptions as any);
} else {
void queryClient.prefetchQuery(queryOptions);
}
}
trpc/server.tsx
tsx
export function HydrateClient(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();
return (
<HydrationBoundary state={dehydrate(queryClient)}>
{props.children}
</HydrationBoundary>
);
}
export function prefetch<T extends ReturnType<TRPCQueryOptions<any>>>(
queryOptions: T,
) {
const queryClient = getQueryClient();
if (queryOptions.queryKey[1]?.type === 'infinite') {
void queryClient.prefetchInfiniteQuery(queryOptions as any);
} else {
void queryClient.prefetchQuery(queryOptions);
}
}

然后你可以像这样使用它:

¥Then you can use it like this:

tsx
import { HydrateClient, prefetch, trpc } from '~/trpc/server';
function Home() {
prefetch(
trpc.hello.queryOptions({
/** input */
}),
);
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrateClient>
);
}
tsx
import { HydrateClient, prefetch, trpc } from '~/trpc/server';
function Home() {
prefetch(
trpc.hello.queryOptions({
/** input */
}),
);
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrateClient>
);
}

利用 Suspense

¥Leveraging Suspense

你可能更喜欢使用 Suspense 和 Error Boundaries 来处理加载和错误状态。你可以使用 useSuspenseQuery 钩子来执行此操作。

¥You may prefer handling loading and error states using Suspense and Error Boundaries. You can do this by using the useSuspenseQuery hook.

app/page.tsx
tsx
import { HydrateClient, prefetch, trpc } from '~/trpc/server';
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { ClientGreeting } from './client-greeting';
export default async function Home() {
prefetch(trpc.hello.queryOptions());
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<Suspense fallback={<div>Loading...</div>}>
<ClientGreeting />
</Suspense>
</ErrorBoundary>
</HydrateClient>
);
}
app/page.tsx
tsx
import { HydrateClient, prefetch, trpc } from '~/trpc/server';
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { ClientGreeting } from './client-greeting';
export default async function Home() {
prefetch(trpc.hello.queryOptions());
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<Suspense fallback={<div>Loading...</div>}>
<ClientGreeting />
</Suspense>
</ErrorBoundary>
</HydrateClient>
);
}
app/client-greeting.tsx
tsx
'use client';
import { useSuspenseQuery } from '@tanstack/react-query';
import { trpc } from '~/trpc/client';
export function ClientGreeting() {
const trpc = useTRPC();
const { data } = useSuspenseQuery(trpc.hello.queryOptions());
return <div>{data.greeting}</div>;
}
app/client-greeting.tsx
tsx
'use client';
import { useSuspenseQuery } from '@tanstack/react-query';
import { trpc } from '~/trpc/client';
export function ClientGreeting() {
const trpc = useTRPC();
const { data } = useSuspenseQuery(trpc.hello.queryOptions());
return <div>{data.greeting}</div>;
}

在服务器组件中获取数据

¥Getting data in a server component

如果你需要访问服务器组件中的数据,我们建议创建服务器调用程序并直接使用它。请注意,此方法与你的查询客户端分离,不会将数据存储在缓存中。这意味着你不能在服务器组件中使用数据并期望它在客户端中可用。这是有意为之,并在 高级服务器渲染 指南中进行了更详细的解释。

¥If you need access to the data in a server component, we recommend creating a server caller and using it directly. Please note that this method is detached from your query client and does not store the data in the cache. This means that you cannot use the data in a server component and expect it to be available in the client. This is intentional and explained in more detail in the Advanced Server Rendering guide.

trpc/server.tsx
tsx
// ...
export const caller = appRouter.createCaller(createTRPCContext);
trpc/server.tsx
tsx
// ...
export const caller = appRouter.createCaller(createTRPCContext);
app/page.tsx
tsx
import { caller } from '~/trpc/server';
export default async function Home() {
const greeting = await caller.hello();
// ^? { greeting: string }
return <div>{greeting.greeting}</div>;
}
app/page.tsx
tsx
import { caller } from '~/trpc/server';
export default async function Home() {
const greeting = await caller.hello();
// ^? { greeting: string }
return <div>{greeting.greeting}</div>;
}

如果你确实需要在服务器上以及客户端组件内部使用数据,并且了解 高级服务器渲染 指南中解释的权衡,则可以使用 fetchQuery 而不是 prefetch 来在服务器上获取数据并将其传输到客户端:

¥If you really need to use the data both on the server as well as inside client components and understand the tradeoffs explained in the Advanced Server Rendering guide, you can use fetchQuery instead of prefetch to have the data both on the server as well as hydrating it down to the client:

app/page.tsx
tsx
import { getQueryClient, HydrateClient, trpc } from '~/trpc/server';
export default async function Home() {
const queryClient = getQueryClient();
const greeting = await queryClient.fetchQuery(trpc.hello.queryOptions());
// Do something with greeting on the server
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrateClient>
);
}
app/page.tsx
tsx
import { getQueryClient, HydrateClient, trpc } from '~/trpc/server';
export default async function Home() {
const queryClient = getQueryClient();
const greeting = await queryClient.fetchQuery(trpc.hello.queryOptions());
// Do something with greeting on the server
return (
<HydrateClient>
<div>...</div>
{/** ... */}
<ClientGreeting />
</HydrateClient>
);
}